Android 读取 SD 卡上的文件
现代的几乎都自带 SD 卡或者可以额外的 SD 卡来扩充手机的存储容量,Android 也支持把 APP 安装到 SD 卡上
当我们使用 Context
的 openFileInput()
或者 openFileOutput()
打开的文件输入输出流时,程序打开的都是 APP 数据文件夹中的文件 /data/data/<应用包名>/file
如果想存储的是视频,音乐等需要占用大量存储空间的,存到手机内存中显得很不明智,一般情况我们都会把这些大文件数据存储到 SD 扩展卡中
SD 卡读写步骤
-
读写前判断 SD 卡是是否插入,是否可读写
Enviroment.getExternalStorageState().equals(Enviroment.MEDIA_MOUNTED);
-
获取 SD 卡的外部目录,同时获得 SD 卡路径
Enviroment.getExternalStorageDirectory().getCanonicalPath();
-
使用
FileOutputStream
、FileInputStream
、FileReader
或FileWriter
读写 SD 卡 -
在
AndroidManifest.xml
中添加 SD 权限: 创建删除文件权限 和 读写数据权限<!-- 在 SD 卡中创建与删除文件权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 往 SD 卡写入数据权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
范例
我们写一个 demo 尝试在 SD 卡上创建文件 site.txt
并写入以下内容
简单教程,简单编程
-
创建一个 空的 Android 项目
cn.twle.android.WriteSDcard
-
修改
activity_main.xml
添加几个TextView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="请输入文件名"/> <EditText android:id="@+id/ms_filename" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="文件名" android:text="site.txt"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请输入文件内容" /> <EditText android:id="@+id/ms_filedata" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="简单教程,简单编程" android:hint="文件内容" /> <Button android:id="@+id/btn_save" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保存到 SD 卡" /> <Button android:id="@+id/btn_clean" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="清空" /> <Button android:id="@+id/btn_read" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读取 SD 卡中的文件" /> </LinearLayout>
-
在
MainActivity.java
同一目录下新建文件SDFileHelper.java
作为读写 SD 卡的帮助类package cn.twle.android.writesdcard; import android.content.Context; import android.os.Environment; import android.widget.Toast; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class SDFileHelper { private Context context; public SDFileHelper() { } public SDFileHelper(Context context) { super(); this.context = context; } //往SD卡写入文件的方法 public void savaFileToSD(String filename, String filecontent) throws Exception { //如果手机已插入sd卡,且 app 具有读写 sd卡 的权限 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { filename = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + filename; //这里就不要用openFileOutput了,那个是往手机内存中写数据的 FileOutputStream output = new FileOutputStream(filename); output.write(filecontent.getBytes()); //将String字符串以字节流的形式写入到输出流中 output.close(); //关闭输出流 } else Toast.makeText(context, "SD卡不存在或者不可读写", Toast.LENGTH_SHORT).show(); } //读取SD卡中文件的方法 //定义读取文件的方法: public String readFromSD(String filename) throws IOException { StringBuilder sb = new StringBuilder(""); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { filename = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + filename; //打开文件输入流 FileInputStream input = new FileInputStream(filename); byte[] temp = new byte[1024]; int len = 0; //读取文件内容: while ((len = input.read(temp)) > 0) { sb.append(new String(temp, 0, len)); } //关闭输入流 input.close(); } return sb.toString(); } }
-
修改
AndroidManifest.xml
加上读写 SD 卡的读写权限<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
修改 MainActivity.java 实现相关逻辑
package cn.twle.android.writesdcard; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import java.io.IOException; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private EditText ms_filename; private EditText ms_filedata; private Button btn_save; private Button btn_clean; private Button btn_read; private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = getApplicationContext(); bindViews(); } private void bindViews() { ms_filename = (EditText) findViewById(R.id.ms_filename); ms_filedata = (EditText) findViewById(R.id.ms_filedata); btn_save = (Button) findViewById(R.id.btn_save); btn_clean = (Button) findViewById(R.id.btn_clean); btn_read = (Button) findViewById(R.id.btn_read); btn_save.setOnClickListener(this); btn_clean.setOnClickListener(this); btn_read.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_clean: ms_filename.setText(""); ms_filedata.setText(""); break; case R.id.btn_save: String filename = ms_filename.getText().toString(); String filedetail = ms_filedata.getText().toString(); SDFileHelper sdHelper = new SDFileHelper(mContext); try { sdHelper.savaFileToSD(filename, filedetail); Toast.makeText(getApplicationContext(), "数据写入成功", Toast.LENGTH_SHORT).show(); } catch(Exception e){ e.printStackTrace(); Toast.makeText(getApplicationContext(), "数据写入失败", Toast.LENGTH_SHORT).show(); } break; case R.id.btn_read: String detail = ""; SDFileHelper sdHelper2 = new SDFileHelper(mContext); try { String filename2 = ms_filename.getText().toString(); detail = sdHelper2.readFromSD(filename2); } catch(IOException e){e.printStackTrace();} Toast.makeText(getApplicationContext(), detail, Toast.LENGTH_SHORT).show(); break; } } }
运行 APP ,演示效果如下
DDMS 查看手机上的文件
DDMS 全名 Dalvik Debug Monitor Service,是 Android 开发环境中的 Dalvik
虚拟机调试监控服务
-
在最新的
Android Studio 3
中,DDMS
已经是顶级窗口之一了,一般会收缩在编辑器的右下角 -
单击
Device File Explore
就会展开当前设备根目录下的所有文件和目录 -
下拉找到一个叫
sdcard
的目录,这就是我们的SD
卡目录,如果你没找到,那就在/mnt/sdcard
目录 -
点击展开
sdcard
目录,一路往下拉一路观察,就会看到我们刚刚创建的文件site.txt
几乎就在最底部,还是名字起的好
-
双击打开
site.txt
,如果是一般的文件,直接双击文件名就会打开
果然读写 SD 卡成功
读写 SD 卡的方法归纳
下面是我整理的一些读写 SD 卡的代码
-
获取SD卡的根目录
String sdcardRoot = Environment.getExternalStorageDirectory().getAbsolutePath();
-
在 SD 卡上创建文件夹目录
public File createDirOnSDCard(String dir) { File dirFile = new File(sdCardRoot + File.separator + dir +File.separator); Log.v("createDirOnSDCard", sdCardRoot + File.separator + dir +File.separator); dirFile.mkdirs(); return dirFile; }
-
在 SD 卡上创建文件
public File createFileOnSDCard(String fileName, String dir) throws IOException { File file = new File(sdCardRoot + File.separator + dir + File.separator + fileName); Log.v("createFileOnSDCard", sdCardRoot + File.separator + dir + File.separator + fileName); file.createNewFile(); return file; }
-
判断文件是否存在于 SD 卡的某个目录
public boolean isFileExist(String fileName, String path) { File file = new File(sdCardRoot + path + File.separator + fileName); return file.exists(); }
-
将数据写入到 SD 卡指定目录文件
public File writeData2SDCard(String path, String fileName, InputStream data) { File file = null; OutputStream output = null; try { createDirOnSDCard(path); //创建目录 file = createFileOnSDCard(fileName, path); //创建文件 output = new FileOutputStream(file); byte buffer[] = new byte[2*1024]; //每次写2K数据 int temp; while((temp = data.read(buffer)) != -1 ) { output.write(buffer,0,temp); } output.flush(); } catch (Exception e) { e.printStackTrace(); } finally{ try { output.close(); //关闭数据流操作 } catch (Exception e2) { e2.printStackTrace(); } } return file; }