前言
之前一直在讲AndroidUI的内容,但是还没有完结,之后会慢慢补充。今天讲讲其他的,关于数据持久化的内容。对于一个应用程序而言,不可避免的要能够对数据进行存储,Android程序也不例外。而在Android中,提供了几种实现数据持久化的方法。后面会分别介绍。
在Android中,可以使用几种方式实现数据持久化:
后面几天会分别介绍以上几种方式实现的数据持久化,对于SharedPreferences而言,之前写过一篇博客,但是自己不是很满意,之后有时间会再重新写一份关于SharedPreferences的博客,有兴趣的朋友可以先去看看,Android--使用SharedPreferences。今天先介绍Internal Storage以及External Storage。
Internal Storage
内部存储,在Android中,开发者可以直接使用设备的内部存储器中保存文件,默认情况下,以这种方式保存的和数据是只能被当前程序访问,在其他程序中是无法访问到的,而当用户卸载该程序的时候,这些文件也会随之被删除。
使用内部存储保存数据的方式,基本上也是先获得一个文件的输出流,然后以write()的方式把待写入的信息写入到这个输出流中,最后关闭流即可,这些都是Java中IO流的操作。具体步骤如下:
上面介绍的Context.openFileOutput()方法有两个重载函数,它们的签名分别是:
上面第二个重载函数中,mode为一个int类型的数据,这个一般使用Context对象中设置好的常量参数,有如下几个:
还有几个方法需要特别注意一下,这几个方法对于文件关系提供了更好的支持,配合上面介绍的方式,就可以对文件的数据进行常规的CRUD操作(增删改查),方法如下:
讲了这么多,下面通过一个简单的Demo来演示一下上面提到的内容。在这个Demo中,指定文件名和内容,既可创建文件,并且可以对其内容进行追加、修改、删除、查询等操作。
布局代码:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <TextView 8 android:layout_width="match_parent" 9 android:layout_height="wrap_content" 10 android:text="file name:" /> 11 12 <EditText 13 android:id="@+id/etInternalFilename" 14 android:layout_width="match_parent" 15 android:layout_height="wrap_content" /> 16 17 <TextView 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 android:text="Content:" /> 21 22 <EditText 23 android:id="@+id/etInternalContent" 24 android:layout_width="match_parent" 25 android:layout_height="wrap_content" /> 26 27 <LinearLayout 28 android:layout_width="match_parent" 29 android:layout_height="wrap_content" 30 android:orientation="horizontal" > 31 32 <Button 33 android:id="@+id/btnInternalSave" 34 android:layout_width="wrap_content" 35 android:layout_height="wrap_content" 36 android:text="save" /> 37 38 <Button 39 android:id="@+id/btnInternalDelete" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:text="delete" /> 43 44 <Button 45 android:id="@+id/btnInternalAppend" 46 android:layout_width="wrap_content" 47 android:layout_height="wrap_content" 48 android:text="append" /> 49 50 <Button 51 android:id="@+id/btnInternalQuery" 52 android:layout_width="wrap_content" 53 android:layout_height="wrap_content" 54 android:text="query" /> 55 </LinearLayout> 56 <!-- 以一个ListView的形式展示当前程序内部存储路径下的所有文件 --> 57 <ListView 58 android:id="@+id/lvInternalData" 59 android:layout_width="match_parent" 60 android:layout_height="fill_parent" > 61 </ListView> 62 63 </LinearLayout>
专门写一个内部存储的操作类,对其实现CRUD操作:
 1 package com.example.internal;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.File;
 5 import java.io.FileInputStream;
 6 import java.io.FileNotFoundException;
 7 import java.io.FileOutputStream;
 8 import java.io.IOException;
 9 
10 import android.content.Context;
11 import android.os.Environment;
12 import android.util.Log;
13 
14 public class MyInternalStorage {
15     //需要保存当前调用对象的Context
16     private Context context;
17 
18     public MyInternalStorage(Context context) {
19         this.context = context;
20     }
21     /**
22      * 保存内容到内部存储器中
23      * @param filename 文件名
24      * @param content 内容
25      */
26     public void save(String filename, String content) throws IOException {
27         // FileOutputStream fos=context.openFileOutput(filename,
28         // Context.MODE_PRIVATE);
29         File file = new File(context.getFilesDir(), filename);
30         FileOutputStream fos = new FileOutputStream(file);
31 
32         fos.write(content.getBytes());
33         fos.close();
34     }
35     /**
36      *  通过文件名获取内容
37      * @param filename 文件名
38      * @return 文件内容
39      */
40     public String get(String filename) throws IOException {
41         FileInputStream fis = context.openFileInput(filename);
42         ByteArrayOutputStream baos = new ByteArrayOutputStream();
43         byte[] data = new byte[1024];
44         int len = -1;
45         while ((len = fis.read(data)) != -1) {
46             baos.write(data, 0, len);
47         }
48         return new String(baos.toByteArray());
49     }
50     /**
51      * 以追加的方式在文件的末尾添加内容
52      * @param filename 文件名
53      * @param content 追加的内容
54      */
55     public void append(String filename, String content) throws IOException {
56         FileOutputStream fos = context.openFileOutput(filename,
57                 Context.MODE_APPEND);
58         fos.write(content.getBytes());
59         fos.close();
60     }
61     /**
62      * 删除文件
63      * @param filename 文件名
64      * @return 是否成功
65      */
66     public boolean delete(String filename) {
67         return context.deleteFile(filename);
68     }
69     /**
70      * 获取内部存储路径下的所有文件名
71      * @return 文件名数组
72      */
73     public String[] queryAllFile() {
74         return context.fileList();
75     }
76 
77 }
Activity代码:
  1 package com.example.datastoragedemo;
  2 
  3 import java.io.IOException;
  4 
  5 import com.example.internal.MyInternalStorage;
  6 
  7 import android.app.Activity;
  8 import android.os.Bundle;
  9 import android.view.View;
 10 import android.view.View.OnClickListener;
 11 import android.widget.AdapterView;
 12 import android.widget.AdapterView.OnItemClickListener;
 13 import android.widget.ArrayAdapter;
 14 import android.widget.Button;
 15 import android.widget.EditText;
 16 import android.widget.ListView;
 17 import android.widget.Toast;
 18 
 19 public class InternalStorageActivity extends Activity {
 20     private EditText etFilename, etContent;
 21     private Button btnSave, btnQuery, btnDelete, btnAppend;
 22     private ListView lvData;
 23 
 24     @Override
 25     protected void onCreate(Bundle savedInstanceState) {
 26         // TODO Auto-generated method stub
 27         super.onCreate(savedInstanceState);
 28         setContentView(R.layout.activity_internalstorage);
 29 
 30         etFilename = (EditText) findViewById(R.id.etInternalFilename);
 31         etContent = (EditText) findViewById(R.id.etInternalContent);
 32         btnSave = (Button) findViewById(R.id.btnInternalSave);
 33         btnQuery = (Button) findViewById(R.id.btnInternalQuery);
 34         btnDelete = (Button) findViewById(R.id.btnInternalDelete);
 35         btnAppend = (Button) findViewById(R.id.btnInternalAppend);
 36         lvData = (ListView) findViewById(R.id.lvInternalData);
 37 
 38         btnSave.setOnClickListener(click);
 39         btnQuery.setOnClickListener(click);
 40         btnDelete.setOnClickListener(click);
 41         btnAppend.setOnClickListener(click);
 42 
 43     }
 44 
 45     private View.OnClickListener click = new OnClickListener() {
 46 
 47         @Override
 48         public void onClick(View v) {
 49             MyInternalStorage myInternal = null;
 50             String filename = null;
 51             String content = null;
 52             switch (v.getId()) {
 53             case R.id.btnInternalSave:
 54                 filename = etFilename.getText().toString();
 55                 content = etContent.getText().toString();
 56                 myInternal = new MyInternalStorage(InternalStorageActivity.this);
 57                 try {
 58                     myInternal.save(filename, content);
 59                     Toast.makeText(InternalStorageActivity.this, "保存文件成功",
 60                             Toast.LENGTH_SHORT).show();
 61                 } catch (IOException e) {
 62                     // TODO Auto-generated catch block
 63                     e.printStackTrace();
 64                     Toast.makeText(InternalStorageActivity.this, "保存文件失败",
 65                             Toast.LENGTH_SHORT).show();
 66                 }
 67 
 68                 break;
 69 
 70             case R.id.btnInternalDelete:
 71                 filename = etFilename.getText().toString();
 72                 myInternal = new MyInternalStorage(InternalStorageActivity.this);
 73                 myInternal.delete(filename);
 74                 Toast.makeText(InternalStorageActivity.this, "删除文件成功",
 75                         Toast.LENGTH_SHORT).show();
 76                 break;
 77             case R.id.btnInternalQuery:
 78                 myInternal = new MyInternalStorage(InternalStorageActivity.this);
 79                 String[] files = myInternal.queryAllFile();
 80                 ArrayAdapter<String> fileArray = new ArrayAdapter<String>(
 81                         InternalStorageActivity.this,
 82                         android.R.layout.simple_list_item_1, files);
 83                 lvData.setAdapter(fileArray);
 84                 Toast.makeText(InternalStorageActivity.this, "查询文件列表",
 85                         Toast.LENGTH_SHORT).show();
 86                 break;
 87             case R.id.btnInternalAppend:
 88                 filename = etFilename.getText().toString();
 89                 content = etContent.getText().toString();
 90                 myInternal = new MyInternalStorage(InternalStorageActivity.this);
 91                 try {
 92                     myInternal.append(filename, content);
 93                     Toast.makeText(InternalStorageActivity.this, "文件内容追加成功",
 94                             Toast.LENGTH_SHORT).show();
 95                 } catch (IOException e) {
 96                     // TODO Auto-generated catch block
 97                     e.printStackTrace();
 98                     Toast.makeText(InternalStorageActivity.this, "文件内容追加失败",
 99                             Toast.LENGTH_SHORT).show();
100                 }
101                 break;
102             }
103 
104         }
105     };
106 
107     private OnItemClickListener itemClick = new OnItemClickListener() {
108 
109         @Override
110         public void onItemClick(AdapterView<?> parent, View view, int position,
111                 long id) {
112             ListView lv = (ListView) parent;
113             ArrayAdapter<String> adapter = (ArrayAdapter<String>) lv
114                     .getAdapter();
115             String filename = adapter.getItem(position);
116             etFilename.setText(filename);
117             MyInternalStorage myInternal = new MyInternalStorage(
118                     InternalStorageActivity.this);
119             String content;
120             try {
121                 content = myInternal.get(filename);
122                 etContent.setText(content);
123             } catch (IOException e) {
124                 // TODO Auto-generated catch block
125                 e.printStackTrace();
126             }
127 
128         }
129     };
130 
131 }
效果展示,在示例中,先添加三个文件,最后删除一个,分别查询文件列表:




使用内部存储的方式进行数据持久化,文件的地址将保存在/data/data/<package_name>/files/路径下,上面创建了三个文件,最后删掉了一个,如果是使用的模拟器,可以直接在File Explorer中查看:

缓存(cache)
既然提到了内部存储,这里再简单的说说关于缓存文件(cache files)。cache files的操作与操作内部存储中的文件方式基本一致,只是获取文件的路径有说不同。如果需要使用缓存的方式进行数据持久话,那么需要使用Context.getCacheDir()方法获取文件保存的路径。
对于缓存文件而言,当设备内部内存存储空间不足的时候,Android会有自动删除的机制删除这些缓存文件,用来恢复可用空间,所以对于缓存文件而言,内容一般最好控制在1MB之下,并且也不要存放重要的数据,因为很可能下次去取数据的时候,已经被Android系统自动清理了。
External Storage
使用外部存储实现数据持久化,这里的外部存储一般就是指的是sdcard。使用sdcard存储的数据,不限制只有本应用访问,任何可以有访问Sdcard权限的应用均可以访问,而Sdcard相对于设备的内部存储空间而言,会大很多,所以一般比较大的数据,均会存放在外部存储中。
使用SdCard存储数据的方式与内部存储的方式基本一致,但是有三点需要注意的:
因为访问Sdcard的方式和访问内部存储的方式差不多,这里就展示一个Save的方法,用于保存文件,其他CRUD操作,这里就不再一一给出了。
 1 public void saveToSdcard(String filename, String content) throws IOException {
 2 
 3         if (Environment.MEDIA_MOUNTED.equals(Environment
 4                 .getExternalStorageState())) {
 5             Log.i("main", "本设备有存储卡!");
 6             File file = new File(Environment.getExternalStorageDirectory(),
 7                     filename);
 8             FileOutputStream fos = null;
 9             fos = new FileOutputStream(file);
10             fos.write(content.getBytes());
11             fos.close();
12         }
13     }
而如果使用SdCard存储文件的话,存放的路径在Sdcard的根目录下,如果使用模拟器运行程序的话,创建的文件在/mnt/sdcard/目录下:

补充:对于现在市面上很多Android设备,自带了一个大的存储空间,一般是8GB或16GB,并且又支持了Sdcard扩展,对于这样的设备,使用Enviroment.getExternalStorageDirectory()方法只能获取到设备自带的存储空间,对于另外扩展的Sdcard而言,需要修改路径。
总结
以上就介绍了内部存储、外部存储、缓存存储的方式方法。开发者可以根据需要选择不同的方式进行数据持久化。
请支持原创,尊重原创,转载请注明出处。谢谢。
原文:http://www.cnblogs.com/shitaotao/p/7635775.html