Android开发中,离不开对文件的操作。本文首先介绍了使用java对文件进行基本的读写操作,而后介绍了Android中读取Assets与raw文件夹中的数据,最后介绍了Android中读写内部存储与外部存储。
一、文件的基本操作
java中file类的定义:An abstract representation of file and directory pathnames.
创建文件时,先实例化file类,再调用createNewFile方法
传入文件路径可以实例化file对象
Filefile=newFile(FileUtil.FILE_NAME);
通过file.exists()可以判断文件是否存在,存在返回true
//创建文件
file.createNewFile();
可以获取文件的各种属性
"文件名为:"+file.getName()"文件的绝对路径为"+file.getAbsolutePath()
//文件存放在工程根目录下,相对路径只有文件名
"文件的相对路径为"+file.getPath();
//文件大小,单位bytes,"文件大小为:"+file.length()+”字节"
"文件是否可读"+file.canRead()"文件是否可写"+file.canWrite()"文件是否隐藏"+file.isHidden()
文件重命名,调用renameTo()方法,需要传入File类作为参数
Filefile=newFile(FileUtil.FILE_NAME);
FilenewFile=newFile("AnotherFile.txt");
file.renameTo(newFile);
文件重命名只针对文件本身,重命名后File对象不变,调用getName()会获得原值
删除文件,当文件存在时,调用delete()方法删除文件
Filefile=newFile(FileUtil.FILE_NAME);
if(file.exists()){file.delete();}
创建文件夹,同样先实例化file类,然后调用mkDir或mkDirs方法进行文件夹的创建
//文件夹,创建多级目录时,不能使用"/"作为分隔符,会因为操作系统的不同而出现异常
//需要使用File.separator(File类中默认的分隔符)
publicstaticfinalStringFOLDER_NAME="NewFolder2"+File.separator+"SubFolder2”;
//当使用file.mkdir时,如果有任意一级的文件夹不存在时都不会完成创建,file.mkdir();
//使用mkdirs创建文件夹时,有文件夹时,创建下一级文件,否则先创建它本身,再创建下一级文件夹
file.mkdirs();创建时尽量使用mkDirs
删除文件夹,调用file.delete()方法
二、读取assets中的文件数据
assets目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
用于储存较小的文件,可以有目录结构,也就是assets目录下可以再建立文件夹
assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类,即不可使用R.id.fileName进行访问
创建assets文件夹
在项目结构管理区,选择project视图,在app/src/main文件夹下,新建assets文件夹
在项目底部根目录下的xxx.iml文件中进行配置(xxx为项目工程名)
在configuration 标签下,添加option子标签
通过getResource()或AssetsManager的getAssets()方法获取字节流,而后通过文件的一般读取方式进行读取。
//通过getAssets获取InputStream获取字节流
InputStream is = getResources().getAssets().open("info.txt");
//将字节流转换为字符流
InputStreamReader isr =newInputStreamReader(is,"UTF-8");
//创建带缓冲区的字符流
BufferedReader bfr =newBufferedReader(isr);
//逐行循环读取文件
String in ="";
while((in = bfr.readLine()) !=null){
Log.i(TAG,in);
}
三、读取raw文件夹中的文件数据
assets目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;
创建raw目录,在res目录下创建raw目录,将文件储存在目录中
通过getResource.openRawResource()将文件读取为字节流,由于文件被影射到R.java文件中,所以参数可以直接使用R.raw.info,而后按照正常的文件读写方式读写
InputStream is = getResources().openRawResource(R.raw.info);
InputStreamReader isr =newInputStreamReader(is);
BufferedReader bfr =newBufferedReader(isr);
String in ="";
try{
while((in = bfr.readLine()) !=null){
Log.i(TAG,in);
}
四、读取内部(internal storage)储存的文件数据
程序运行后,在当前应用下的data->data->应用目录下的储存空间为文件内部储存空间包含cache和code_cache,只对当前应用可见。使用OpenFileOutput(filename,写入模式)方法,可以在应用内部储存中自动创建files文件夹,在files文件夹中,创建相应文件名的文件。
读取数据:程序从输入流读取数据,数据源为键盘,网络,文件等。
写入数据:程序向输出流写入数据,将程序中的数据输出到显示器,文件,网络
写入数据:调用OpenFileOutput(filename,写入模式)方法,得到FileOutputStream,包装成OutputStreamWriter,然后调用write方法进行写入,冲刷缓冲区,关闭流
//文件输出流,第二个参数为写入模式,使用openFileOutPut()方法输出的文件在
//应用程序内部储存空间
FileOutputStream fos = openFileOutput(flieName,Context.MODE_PRIVATE);
//将文件输出流进一步包装,变为可写入字符串的OutPutStreamWriter
OutputStreamWriter osw =newOutputStreamWriter(fos,"UTF-8");
osw.write(et.getText().toString());
//执行flush操作,将缓冲区的数据全部输出
osw.flush();
fos.flush();
//关闭流,后打开的流先关闭
osw.close();
fos.close();
Toast.makeText(MainActivity.this,"写入完成",Toast.LENGTH_SHORT).show();
读取数据:调用OpenFileInput(filename)方法,得到FileInputStream,包装成InputStreamReader,创建字符数组,然后调用read方法进行读取,没有冲刷缓冲区。记得关闭流,可将字符数组转换为 String
//openFileInput()只有一个参数,即需要读取的文件名
FileInputStream fis = openFileInput(flieName);
//包装成为InputStreamReader,可调用read方法
InputStreamReader isr =newInputStreamReader(fis,"UTF-8");
//创建字符数组,通过fis.available()获取字符流中可用字符的长度
charinput[] =new char[fis.available()];
//将字符流读入字符数组
isr.read(input);
isr.close();
fis.close();
//将字符数组转为String
String text =newString(input);
//将string设置为TextView的内容
tv.setText(text);
五、读取外部储存(external storage)的文件数据
外部储存类似 sd card,一些设备将"internal" 与 "external" 都做成了不可卸载的内置存储,虽然如此,但是这一整块还是从逻辑上有被划分为"internal"与”external”.
Internal storage:
总是可用的
这里的文件默认只能被我们的app所访问。
当用户卸载app的时候,系统会把internal内该app相关的文件都清除干净。
Internal是我们在想确保不被用户与其他app所访问的最佳存储区域。
External storage:
并不总是可用的,因为用户有时会通过USB存储模式挂载外部存储器,当取下挂载的这部分后,就无法对其进行访问了。
是大家都可以访问的,因此保存在这里的文件可能被其他程序访问。
当用户卸载我们的app时,系统仅仅会删除external根目录(getExternalFilesDir())下的相关文件。
External是在不需要严格的访问权限并且希望这些文件能够被其他app所共享或者是允许用户通过电脑访问时的最佳存储区域。尽管app是默认被安装到internal storage的,我们还是可以通过在程序的manifest文件中声明android:installLocation属性来指定程序安装到external storage。
获取external storage权限:写入权限需要在Manifest文件中添加
读取权限默认目前默认拥有,为确保准确可以声明
当声明拥有写入外部储存权限时,自动拥有读取外部储存的权限
使用Environment.getExternalStorageDirectory()获取系统SD卡路径
当最小sdk小于23时,虽然在manifest文件中声明了权限。应用启动时需要仍需要请求使用外部储存。设置判断是否请求权限与请求权限的函数
//判断是否请求外部储存权限
protected booleanshouldAskPermissions() {
return(Build.VERSION.SDK_INT> Build.VERSION_CODES.LOLLIPOP_MR1);
}
//当最小sdk小于23时,请求外部储存权限
@TargetApi(23)
protected voidaskPermissions() {
String[] permissions = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
};
intrequestCode =200;
requestPermissions(permissions,requestCode);
}
在onCreate函数中进行调用
External storage对其他应用与用户可访问修改,其中文件分为两类:public private
public:对其他用户有用,应用卸载时应保留,例如下载的文件,拍摄的照片,保存的音乐
private:虽然技术上可以访问,但对其他应用无用,应用卸载时自动删除,主要为缓存
储存在public时,使用getExternalStoragePublicDirectory()方法,参数为特定的文件类型
通过Environment.Directory获得
//定义一个储存在ExternalStorage的public的文件,参数必须为特定的文件类型:DIRECTORY_MUSIC 或者 DIRECTORY_PICTURES
Filesdcard= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
储存在private时,使用getExternalStorageDirectory()方法,指定文件类型参数会储存在private的参数文件夹下,不指定类型,储存在private根目录下
//在外部储存private的根目录下新建文件夹pictures
StringfilePath= Environment.getExternalStorageDirectory()+"/Pictures”;
获取路径后,按正常文件操作读写
写入操作:
// 判断设备sd卡是否存在
if(!sdcard.exists()){
Toast.makeText(getApplicationContext(),"sd卡不存在",Toast.LENGTH_SHORT).show();
return;
}
//文件不存在创建文件
if(!myFile.exists()){
try{
myFile.createNewFile();
}catch(IOException e) {
Log.e("文件创建失败",e.getMessage());
e.printStackTrace();
}
//文件写入操作
try{
FileOutputStream fos =newFileOutputStream(myFile);
OutputStreamWriter osw =newOutputStreamWriter(fos);
osw.write(et.getText().toString());
osw.flush();
fos.flush();
osw.close();
fos.close();
Toast.makeText(getApplicationContext(),"数据写入成功",Toast.LENGTH_SHORT).show();
}catch(FileNotFoundException e) {
Log.e("文件没找到",e.getMessage());
e.printStackTrace();
}catch(IOException e) {
Log.e("io错误",e.getMessage());
e.printStackTrace();
}
读取操作:
// 判断设备sd卡是否存在
if(!sdcard.exists()){
Toast.makeText(getApplicationContext(),"sd卡不存在",Toast.LENGTH_SHORT).show();
return;
}
//文件不存在创建文件
if(!myFile.exists()) {
try{
myFile.createNewFile();
}catch(IOException e) {
e.printStackTrace();
}
try{
FileInputStream fis =newFileInputStream(myFile);
InputStreamReader isr =newInputStreamReader(fis);
BufferedReader br =newBufferedReader(isr);
//StringBuilder储存所有数据
StringBuilder strBuilder =newStringBuilder();
//临时变量储存每行数据
String line ="";
while((line = br.readLine()) !=null) {
//不为空,不断追加
strBuilder.append(line);
}
br.close();
isr.close();
fis.close();
Toast.makeText(MainActivity.this,"数据读取成功",Toast.LENGTH_SHORT).show();
tv.setText(strBuilder);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}