数据持久化是保证数据在程序销毁、设备关机后仍然不会丢失的操作,Android系统上主要有三种方式。第二个再说说文件读写,在日常开发中很多数据是以文件的形式进行存储的,根据文件的位置存在四种不同的读写方式,主要包括raw、assets、InternalStorage、ExternalStorage。
本文已收录至☞Android学习路线_梳理 上一篇☞Android学习路线_入门篇(八)数据持久化之SharedPreferences 下一篇☞Android学习路线_入门篇(十)数据持久化之数据库
1. raw文件
raw文件是在项目中的res/raw
文件夹下,res/raw
中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即可。
通过getResource.openRawResource()将文件读取为字节流,由于文件被影射到R.java文件中,所以参数可以直接使用R.raw.info,而后通过文件的一般读取方式进行读取。
InputStream is = getResources().openRawResource(R.raw.info);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bfr = new BufferedReader(isr);
String in = "";
try{
while((in = bfr.readLine()) != null){
Log.i(TAG, in);
}
} catch (Exception e) {
e.printStackTrace();
}
is.close();
2. assets文件
assets目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制,可以有目录结构,也就是assets目录下可以再建立文件夹。
通过getResource()或AssetsManager的getAssets().open(文件名)方法获取字节流,而后通过文件的一般读取方式进行读取。
InputStream is = getResources().getAssets().open("info.txt");
InputStreamReader isr =newInputStreamReader(is,"UTF-8");
BufferedReader bfr =newBufferedReader(isr);
String in ="";
try{
while((in = bfr.readLine()) != null){
Log.i(TAG, in);
}
} catch (Exception e) {
e.printStackTrace();
}
is.close();
3. InternalStorage文件
内部存储(Internal Storage)总是可用的,文件默认情况存储在/data/data/包名/files,缓存文件存储在/data/data/包名/cache中,默认情况下只能只能被本APP操作,当然可以在openFileOutput()中指定是否可被其他app读写。
当使用者卸载你的app时,系统会自动从内部存储中删除你的app对应文件夹下的所有文件。
使用OpenFileOutput(filename,写入模式)方法,可以在应用内部储存中自动创建files文件夹,在files文件夹中,创建相应文件名的文件。
3.1 写入数据
调用OpenFileOutput(filename,写入模式)方法,得到FileOutputStream,包装成OutputStreamWriter,然后调用write方法进行写入,冲刷缓冲区,关闭流。
try{
String content = "写入数据内容";
FileOutputStream fos = openFileOutput("info.text",Context.MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
osw.write(content);
osw.flush();
fos.flush();
osw.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
3.2 读取数据
调用OpenFileInput(filename)方法,得到FileInputStream,包装成InputStreamReader,创建字符数组,然后调用read方法进行读取,没有冲刷缓冲区。记得关闭流,可将字符数组转换为 String。
try{
FileInputStream fis = openFileInput("info.text");
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
charinput[] = new char[fis.available()];
isr.read(input);
isr.close();
fis.close();
String in = new String(input);
Log.i(TAG, in);
} catch (Exception e) {
e.printStackTrace();
}
4. ExternalStorage文件
外部存储(External storage)并不是总是可用,因为用户有可能将SD卡作为USB存储挂载或者在某些情况下将SD卡从设备上卸下,因此需要使用getExternalStorageState()来查询外部存储的状态,当返回的状态是MEDIA_MOUNTED时才能读写。一些设备将"internal" 与 “external” 都做成了不可卸载的内置存储,虽然如此,但是这一整块还是从逻辑上有被划分为"internal"与”external”。
保存在外部存储的文件是world-readable的,所以保存在外部存储的文件可能被其他应用读取。
当用户卸载你的app时,系统只会删除你的app中通过调用getExternalFilesDir()来保存的文件。
并且在使用外部存储时还需要在AndroidManifest文件中申请对应的权限:
// 向SD卡写入数据权限,隐式授予了读取权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
// 当app只需要读取而非写入权限的时候更适合使用该权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
// 在SD卡中创建和删除文件权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
4.1 写入数据
首先通过Environment.getExternalStorageState()判断SD卡的状态,随后根据写入位置和文件名称拿到对应的File对象,并对文件路径和文件进行创建,最后将数据写入文件并关闭输出流。
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)){
Toast.makeText(getApplicationContext(),"sd卡不可写入",Toast.LENGTH_SHORT).show();
return;
}
String fileName = "info.text";
String content = "写入数据内容";
File myFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), fileName);
if (!myFile.mkdirs()){
Log.d(TAG,"Directory not create");
}
if(!myFile.exists()){
try{
myFile.createNewFile();
}catch(IOException e) {
Toast.makeText(getApplicationContext(),"文件创建失败",Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
try{
FileOutputStream fos =newFileOutputStream(myFile);
OutputStreamWriter osw =newOutputStreamWriter(fos);
osw.write(content);
osw.flush();
fos.flush();
osw.close();
fos.close();
}catch(Exception e) {
e.printStackTrace();
}
4.2 读取数据
首先通过Environment.getExternalStorageState()判断SD卡的状态,随后根据读取位置和文件名称拿到对应的File对象,并对文件路径和文件进行创建,最后将文件中的数据进行读取并关闭输入流。
String state=Environment.getExternalStorageState();
if (!(Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))){
Toast.makeText(getApplicationContext(),"sd卡不可读取",Toast.LENGTH_SHORT).show();
return;
}
String fileName = "info.text";
File myFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), fileName);
if (!myFile.mkdirs()){
Log.d(TAG,"Directory not create");
}
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 strBuilder =newStringBuilder();
String line ="";
while((line = br.readLine()) !=null) {
strBuilder.append(line);
}
br.close();
isr.close();
fis.close();
Log.i(TAG, strBuilder.toString());
}catch(Exception e) {
e.printStackTrace();
}