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();
结果:
第五步:获取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权限需要动态获取
//可写
//可读
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:
在强者的眼中,没有最好,只有更好