共计 7730 个字符,预计需要花费 20 分钟才能阅读完成。
Android 数据存储之 SP 存储,外部存储,内部存储
Android 提供了多种数据存储的技术来永恒的保留利用数据,以便于开发者可能依据本人的需要来抉择适合的数据存储计划,次要有 SharedPreferences, 外部存储 (Internal Storage), 内部存储 (External Storage),SQLite 数据库, 网络存储等
一:SharedPreferences
第一步:getSharedPreferences 办法获取到 SharedPreferences 对象。零碎会在 /data/data/ 包名 /shared_prefs 目录下生成一个 ** 文件
Context.MODE_PRIVATE: 默认的文件创建模式。应用该模式创立文件,如果文件目录中已存在同名文件,则新建的文件会笼罩旧文件。并且,文件只能由创立文件的利用(或者与该利用共享同一 user ID 的利用)所拜访。
Context.MODE_APPEND:应用该模式创立文件,如果文件目录中已存在同名文件,则新的内容将间接被增加到旧文件的尾部,而不会新建一个文件来笼罩旧文件。
Context.MODE_WORLD_READABLE:使其余利用对文件具备读的权限。
Context.MODE_WORLD_WIRTEABLE:使其余利用对文件具备写的权限。
留神:从 API Level 17 当前,MODEWORLDREADABLE 和 MODEWORLDWRITEABLE 曾经被弃用。从 Android N(即 7.x)开始,应用这两个常量会导致 SecurityException。这意味着面向 Android N 和更高版本的利用无奈按名称共享公有文件,尝试共享“file://” 类型的 URI 将会导致 FileUriExposedException。
第二步:通过 SharedPreferences 对象的 edit()办法获取一个 SharedPreferences.Editor 对象
第三步:调用 putBoolean()(或者 putString()、putInt()等,由要保留的数据的数据类型而定)等办法增加值
第四步:应用提交 commit()办法有返回值 boolean 类型和 apply()无返回值
/* 获取 SharedPreferences 对象
1. 第一个参数为 name: 示意文件名,零碎会在 /data/data/ 包名 /shared_prefs 目录下生成一个以该参数命名的.xml 文件
2. 第二个 mode 示意创立的模式,倡议为 0 或者 MODE_PRIVATE
* */
SharedPreferences sp = getSharedPreferences("test_sp", MODE_PRIVATE);
// 获取 Editor 对象
SharedPreferences.Editor editor = sp.edit();
// 依据要保留的数据类型,调用对应的 put 办法
// 以键值对模式增加
editor.putString("data", "我是 Rocky");
// 提交新值,必须执行否则后面操作有效
editor.commit();
后果:
<map>
<string name="data"> 我是 Rocky</string>
</map>
第五步:获取 SP 数据
// 依据保留时所用的 name 属性,获取 SharedPreferences 对象
SharedPreferences sp=getSharedPreferences("test_sp",MODE_PRIVATE);
// 依据数据类型,调用对应的 get 办法,通过键获得对应的值。String aa=sp.getString("data",null);
Log.d("aa",aa);
后果:D/aa: 我是 Rocky
二:外部存储
外部存储创立公有文件:文件目录 /data/data/ 包名 /files
写入文件 test_file
// 文件名
String file_name="test_file";
// 写入内容
String content="Hello Android!";
try {
// 写出数据,以程序为核心,写出数据到文件中
FileOutputStream fos=openFileOutput(file_name,MODE_PRIVATE);
// 调用 write 写入数据
fos.write(content.getBytes());
// 调用 close()敞开数据流
fos.close();} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
后果:Hello Android!
要从外部存储中读取文件,步骤如下:
1. 应用要读取的文件的文件名作为参数,调用 openFileInput()办法,返回一个 FileInputStream 实例。
2. 调用 read()办法读取文件字节。
3. 字节数组转成 String 类型
4. 调用 close() 办法敞开流式传输。
private FileInputStream fis;
// 用于存储数据流的 byte 数组
byte[] bytes=new byte[1024];//1024 个字节数组是 1kB
int read=0;// 失去工夫读取的字节数,读带最初返回 -1;
try {
// 调用 openFileInput,返回一个 FileInputStream
fis = openFileInput(file_name);
// 循环读取
while ((read= fis.read(bytes))!=-1){// 把 fis 里的货色读到 bytes 数组里去
// // 把字节转成 String 从 0 到 read 变成 String
String s=new String(bytes,0,read);
Log.d("s",s);
}
} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}finally {
try {fis.close();
} catch (IOException e) {e.printStackTrace();
}
}
后果:D/s: Hello Android!
留神:文件的读写操作是耗时操作,因而最好不要在主线程(UI 线程)中执行,防止程序呈现 ANR(程序未响应)。并且,在每次操作完结后,要记得调用 close()办法敞开对应的输出流或者输入流,以开释系统资源。
三:外部存储缓存文件
文件目录:data/data/ 包名 /cache
当有一些文件只需长期应用,不用永恒保留的时候,应该把这些文件保留在外部存储的缓存目录中。保留在外部存储的缓存目录中的文件,当设施外部存储空间有余时,零碎可能会首先删除这些缓存文件以开释内存空间。然而,开发者不应该依赖零碎来清理这些文件,而应该始终自行保护缓存文件,使其占用的空间放弃在正当的限度范畴内(如 1MB)。当利用被卸载时,缓存文件也会被移除。
// 文件名
String file_cache_name="test_cache_file";
// 写入内容
String cache_content="Hello Cache World";
// 应用 getCacheDir()办法获取外部存储缓存目录
File cacheDir=getCacheDir();// 这个拿到得是 cache 目录构造
// 结构文件门路,/data/data/ 包名 /cache/ 文件名
// 通过这种形式指明文件要保留在外部存储缓存目录中。String cache_file=cacheDir+"/"+file_cache_name;
try {
// 通过 FileOutputStream 的构造方法传入结构好
// 的文件门路,返回一个 FileOutputStream 实例。// 留神:这里没有再应用 openFileOutput,是因
// 为 openFileOutput 参数不容许蕴含门路分隔符“/”,
// 如果持续应用 openFileOutput 办法,将会呈现
//IllegalArgumentException 异样
FileOutputStream cache_fos=new FileOutputStream(cache_file);
// 调用 write()办法写入数据
cache_fos.write(cache_content.getBytes());
// 调用 close()敞开输入流
cache_fos.close();} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
后果:Hello Cache World
读取外部存储缓存目录文件的缓存文件
// 文件名
String file_cache_name="test_cache_file";
private FileInputStream inputStream;
// 用于存储数据流的 byte 数组
byte[] bytes=new byte[1024];
int read=0;// 失去工夫读取的字节数,读带最初返回 -1;
try {File cache=getCacheDir();
String cache_file=cache+"/"+file_cache_name;
inputStream = new FileInputStream(cache_file);
while ((read= inputStream.read(bytes))!=-1){
// // 把字节转成 String 从 0 到 read 变成 String
String c=new String(bytes,0,read);
Log.d("c",c);
}
} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}finally {
try {inputStream.close();
} catch (IOException e) {e.printStackTrace();
}
}
后果:D/c: Hello Cache World
对于外部存储中文件和目录的操作实用的办法
getFilesDir(): 获取存储外部文件的文件系统目录的绝对路径。即 /data/data/ 包名 /files
getDir(String name,int mode):在外部存储空间中新建(或关上现有的)目录。即在 data/data/ 包名 目录下新建(或关上现有的)目录
deleteFile(String name):删除 /data/data/ 包名 /files 目录下 name 属性指定的文件。此办法参数不能蕴含门路分隔符“/”,间接传入要删除的文件的文件名即可。
fileList():列出 /data/data/ 包名 /files 目录下所有文件的文件名。
四:内部存储(External Storage)
所有的兼容 Android 的设施都反对一个共享的可能让用户保留文件的内部存储。这个内部存储可能是一个可移植的存储介质(SD 卡),或者是零碎在本身的外部存储器上所调配进去用作内部存储的分区。包含设施上的一些公共目录,如手机相册(Pictures), 音乐(Music)等目录。存储在内部存储中的文件是全局可读写文件。
1. 内部存储须要增加拜访权限,在 AndroidManifest.xml 文件中,Android6.0 权限须要动静获取
// 可写
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
// 可读
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 判断以后设施的状态
Environment.getExternalStorageState() 返回内部存储设备以后的状态
Environment.getDataDirectory() 返回 file,获取 data 的根目录
Environment.getRootDirectory() 返回 File,获取 Android 的根目录
D/aa: mounted
D/aa: /data
D/aa: /system
Environment.MEDIA_MOUNTED 等于 ”mounted”,代表 SD 卡挂载,可读写
Environment.MEDIA_UNMOUNTED 等于 ”unmounted”, 有介质未挂载 不可读写
等
// 获取内部存储的可用性
String state=Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)){return true;}
3. 获取内部存储相册的门路
File picDirectory2= getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// 获取设施的相册目录
File picDirectory =Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Log.d("aa",picDirectory2.getAbsolutePath());
Log.d("aa",picDirectory.getAbsolutePath());
后果:D/aa: /storage/emulated/0/Android/data/com.ruan.testw/files/Pictures
D/aa: /storage/emulated/0/Pictures
// 获取外部设备的状态
String state=Environment.getExternalStorageState();
// 如果外设能够用
if (Environment.MEDIA_MOUNTED.equals(state)){File picDirectory2= getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// 获取设施的相册目录
File picDirectory =Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Log.d("aa",picDirectory2.getAbsolutePath());
Log.d("aa",picDirectory.getAbsolutePath());
File file=new File(picDirectory2,"My_pic");// 第一个参数父文件,第二个文件是子文件
if (!file.exists()){// 如果文件不存在,创立一个新的文件
try {file.createNewFile();
} catch (IOException e) {e.printStackTrace();
}
}
File picDirectory3= getExternalCacheDir();
Log.d("aa",picDirectory3.getAbsolutePath());
后果:D/aa: /storage/emulated/0/Android/data/com.ruan.testw/cache
// 获取外部设备的状态
String state=Environment.getExternalStorageState();
String cont="我在内部存储文件中";
// 如果外设能够用
if (Environment.MEDIA_MOUNTED.equals(state)){String file_path=Environment.getExternalStorageDirectory().getAbsolutePath();
Log.d("aa",file_path);
}
File file=new File(file_path+"/"+"My_Test");
if (!file.exists()){file.mkdir();// 创立文件夹
}else {
FileOutputStream fileOutputStream= null;
try {File file1=new File(file,"wo");
fileOutputStream = new FileOutputStream(file1);
fileOutputStream.write(cont.getBytes());
fileOutputStream.flush();
fileOutputStream.close();} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
}
}
后果:内容写入到 D /aa: /storage/emulated/0/My_Test/wo 文件下
我在内部存储文件中
总结:
1.Environment.getExternalStorageDirectory() 获取内部存储的目录
/storage/emulated/0
2.Environment.getRootDirectory() 获取存储的零碎 system 目录
/system
3.Environment.getDataDirectory() 获取 data 目录
/data
4.Environment.getDownloadCacheDirectory() 获取 data 目录下
/data/cache
5.getExternalCacheDir()// 获取内部存储包名下的 cache
/storage/emulated/0/Android/data/com.ruan.testw/cache
6.getCacheDir() 获取外部存储下 cache
/data/data/com.ruan.testw/cache
7.getFilesDir()获取外部存储下 files
/data/user/0/com.ruan.testw/files=/data/data/com.ruan.testw/files
8.getExternalFilesDir(Environment.DIRECTORY_DCIM)获取内部存储的包名下 files 文件 // 参数是一个 String 的“aa”都能够
/storage/emulated/0/Android/data/com.ruan.testw/files/DCIM
9.getSharedPreferences(“test_sp”, MODE_PRIVATE); 获取 SharedPreferences 对象
/data/data/ 包名 /shared_prefs/test_sp
END:
在强人的眼中,没有最好,只有更好