概述
在Android开发中,存储(Storage)的方式根据具体的需求不同而不同,例如数据对应用程序是私有的还是其他应用程序(和用户)可以访问的,以及保存数据需要多大的空间。
存储分类
主要的存储方式有以下几种(本文主要涉及前三种):
- Shared Preferences:以键值对( key-value pairs)的方式存储在程序内部;
- Internal Storage:将数据保存在设备内存中;
- External Storage:将公有数据保存在外部存储中(SD卡);
- SQLite Databases:保存结构化数据到私有数据库中;
- Network Connection:通过网络服务器,将数据存储在web上。
涉及知识点
涉及的知识点如下:
- SharedPreferences 共享目录接口,通过Context中的getSharedPreferences进行实例化。
- SharedPreferences.Editor 共享目录编辑器,需要以commit进行保存。
- FileOutputStream 文件输出流,用write方法将数据保存文件。
- FileInputStream 文件输入流,用于读取文件的内容,通过Context中的openFileInput进行实例化,用read方法进行读取内容。
- deleteFile Context中的方法,删除指定路径的文件
- Environment.getExternalStorageDirectory() 获取外部存储的根目录。
- Environment.getExternalStorageState() 获取外部存储卡的状态。
- File.separator 文件路径分割符,用斜杠(/)进行表示。
- BitmapFactory.decodeResource(getResources(), R.drawable.bg) 通过资源文件实例化对象。
- BitmapFactory.decodeFile(imgFile.getAbsolutePath() 通过具体文件的路径实例化对象。
- File 文件对象,mkdirs() 创建多层目录 mkdirs创建单个目录,exists() 判断文件或目录是否存在,createNewFile() 创建新文件。
Shared Preferences
此种方式,只能保存简单的数据类型如下图所示:
代码如下:
1 /**
2 * SharedPreferences保存
3 * @param v
4 */
5 public void sharedSave(View v){
6 String name=etName.getText().toString().trim();
7 String age=etAge.getText().toString().trim();
8 if(TextUtils.isEmpty(name)||TextUtils.isEmpty(age)){
9 return;
10 }
11 //构造一个编辑器----笔
12 SharedPreferences.Editor editor = sp.edit();
13 //数据的存储---只能存储简单的数据
14 editor.putString("name",name);
15 editor.putString("age",age);
16 //提交--保存
17 editor.commit();
18 //清空
19 etName.setText("");
20 etAge.setText("");
21 }
22
23 /**
24 * SharedPreferences读取
25 */
26 public void sharedRedo(View v){
27 String name=sp.getString("name","");
28 String age=sp.getString("age","");
29 etName.setText(name);
30 etAge.setText(age);
31 }
Internal Storage
将数据内容转换为字节的方式保存在文件中,如下图所示:
代码如下:
1 /**
2 * 内部保存
3 * @param v
4 */
5 public void internalSave(View v) {
6 String name = etName.getText().toString().trim();
7 String age = etAge.getText().toString().trim();
8 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(age)) {
9 return;
10 }
11
12 try {
13 String content = "这是我的姓名:" + name + "这是我的年龄:" + age;
14 FileOutputStream fos = openFileOutput(sname, MODE_PRIVATE);
15 fos.write(content.getBytes());
16 fos.close();
17 etName.setText("");
18 etAge.setText("");
19 } catch (IOException e) {
20 e.printStackTrace();
21 }
22 }
23
24 /**
25 * 内部读取
26 * @param v
27 */
28 public void internalRedo(View v) {
29 try {
30 FileInputStream fis = openFileInput(sname);
31 byte[] buffer = new byte[fis.available()];
32 fis.read(buffer);
33 fis.close();
34 String content = new String(buffer);
35 Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
36 } catch (IOException e) {
37 e.printStackTrace();
38 }
39 }
40
41 /**
42 * 删除文件
43 * @param v
44 */
45 public void internalDel(View v){
46 boolean del=deleteFile(sname);
47 if(del){
48 Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
49 }else{
50 Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
51 }
52 }
External Storage
在外部存储中,需要在AndroidManifest.xml中配置相关的读写权限,如下所示:
1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
3 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
保存在SD卡中,如下图所示:
代码如下:
1 /**
2 * 外部存储
3 * @param v
4 */
5 public void externalSave(View v) {
6
7 try {
8 Log.i(TAG, "externalSave: 开始");
9 Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
10 ByteArrayOutputStream bass = new ByteArrayOutputStream();
11 img.compress(Bitmap.CompressFormat.JPEG, 100, bass);
12 img.recycle();
13 Log.i(TAG, "externalSave: saveImg");
14 boolean saveOk = saveImg("dog.jpg", bass.toByteArray());
15 Log.i(TAG, "externalSave: saveImg:"+saveOk);
16 if (saveOk) {
17 Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
18 }
19 bass.close();
20 Log.i(TAG, "externalSave: 结束");
21 } catch (IOException e) {
22 e.printStackTrace();
23 Log.i(TAG, "externalSave: 异常"+e.getMessage());
24 }
25 }
26
27 /**
28 * 外部读取
29 * @param v
30 */
31 public void externalRedo(View v) {
32 if (!isMounted()) {
33 return;
34 }
35 try {
36 Bitmap img = readImg("dog.jpg");
37 iv01.setImageBitmap(img);
38 } catch (Exception e) {
39 e.printStackTrace();
40 }
41 }
42
43 private boolean saveImg(String fileName,byte[] data){
44 Log.i(TAG, "saveImg: 开始");
45 if(!isMounted()){
46 Log.i(TAG, "saveImg: 挂载失败");
47 return false;
48 }
49 Log.i(TAG, "saveImg: 路径:"+storedPath);
50 File dir=new File(storedPath);
51 if(!dir.exists()){
52 boolean f= dir.mkdirs();
53 if(f){
54 Log.i(TAG, "saveImg: 创建目录成功:"+storedPath);
55 }else{
56 Log.i(TAG, "saveImg: 创建目录失败:"+storedPath);
57 }
58 }
59 Log.i(TAG, "saveImg: 判断路径:ok");
60 try {
61 File file=new File(storedPath,fileName);
62 if(file.exists()){
63 Log.i(TAG, "saveImg: 判断文件:1");
64 file.delete();
65 }
66 Log.i(TAG, "saveImg: 判断文件:2");
67 file.createNewFile();
68 Log.i(TAG, "saveImg: 判断文件:ok");
69 FileOutputStream fos=new FileOutputStream(file);
70 fos.write(data);
71 fos.close();
72 return true;
73 } catch (IOException e) {
74 e.printStackTrace();
75 Log.i(TAG, "saveImg: 异常:"+e.getMessage());
76 return false;
77 }
78 }
79
80 public Bitmap readImg(String fileName){
81 if(!isMounted()){
82 return null;
83 }
84 File imgFile=new File(storedPath,fileName);
85 if(imgFile.exists()){
86 return BitmapFactory.decodeFile(imgFile.getAbsolutePath());
87 }
88 return null;
89 }
90
91 private boolean isMounted(){
92 String state=Environment.getExternalStorageState();
93 return state.equals(Environment.MEDIA_MOUNTED);
94 }
备注
在进行外部存储时,如果默认关闭了APP的存储空间权限,没有前往设置开启应用权限,即使manifest中正常注册权限,该APP仍让无法读写文件。调试日志如下:
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
未开启App的存储权限
04-02 21:21:59.173 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 开始
04-02 21:21:59.407 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:21:59.408 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 开始
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 路径:/storage/emulated/0/hex/images
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判断路径:ok
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:2
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 异常:No such file or directory
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg:false
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 结束
开启App的存储权限
04-02 21:22:48.519 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 开始
04-02 21:22:48.754 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:22:48.755 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 开始
04-02 21:22:48.759 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 路径:/storage/emulated/0/hex/images
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断路径:ok
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:2
04-02 21:22:48.761 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:ok
04-02 21:22:48.763 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg:true
04-02 21:22:48.787 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 结束
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
记录学习,记录成长!