Android--資料持久化之內部儲存、Sdcard儲存

來源:互聯網
上載者:User

標籤:一點   路徑   索引值   rom   auto   bool   tle   部落格   row   

前言

  之前一直在講AndroidUI的內容,但是還沒有完結,之後會慢慢補充。今天講講其他的,關於資料持久化的內容。對於一個應用程式而言,不可避免的要能夠對資料進行儲存,Android程式也不例外。而在Android中,提供了幾種實現資料持久化的方法。後面會分別介紹。

  在Android中,可以使用幾種方式實現資料持久化:

  • Shared Preferences:共用參數形式,一種以Key-Value的索引值對形式儲存資料的方式,Android內建的,一般應用的配置資訊,推薦使用此種方式儲存。
  • Internal Storage:使用Android裝置內建的記憶體儲存資料。
  • External Storage:使用外部存放裝置儲存資料,一般是指Sdcard。
  • SQLite Databases:以SQLite資料庫儲存結構化的資料。
  • Network Connection:使用基於網路的服務擷取資料,可以參見另外一篇部落格:Android--Apache HttpClient。

  後面幾天會分別介紹以上幾種方式實現的資料持久化,對於SharedPreferences而言,之前寫過一篇部落格,但是自己不是很滿意,之後有時間會再重新寫一份關於SharedPreferences的部落格,有興趣的朋友可以先去看看,Android--使用SharedPreferences。今天先介紹Internal Storage以及External Storage。

Internal Storage

  內部儲存,在Android中,開發人員可以直接使用裝置的內部儲存空間中儲存檔案,預設情況下,以這種方式儲存的和資料是只能被當前程式訪問,在其他程式中是無法訪問到的,而當使用者卸載該程式的時候,這些檔案也會隨之被刪除。

  使用內部儲存儲存資料的方式,基本上也是先獲得一個檔案的輸出資料流,然後以write()的方式把待寫入的資訊寫入到這個輸出資料流中,最後關閉流即可,這些都是Java中IO流的操作。具體步驟如下:

  • 使用Context.openFileOutput()方法擷取到一個FileOutputStream對象。
  • 把待寫入的內容通過write()方法寫入到FileOutputStream對象中。
  • 最後使用close()關閉流。

  上面介紹的Context.openFileOutput()方法有兩個重載函數,它們的簽名分別是:

  • FileOutputStream openFileOutput(String name):以MODE_PRIVATE的模式開啟name檔案。
  • FileOutputStream openFileOutput(String name,int mode):以mode的模式開啟name檔案。

  上面第二個重載函數中,mode為一個int類型的資料,這個一般使用Context對象中設定好的常量參數,有如下幾個:

  • MODE_APPEND:以追加的方式開啟一個檔案,使用此模式寫入的內容均追加在原本內容的後面。
  • MODE_PRIVATE:私人模式(預設),如果檔案已經存在會重新建立並替換原檔案,如果不存在直接建立。
  • MODE_WORLD_READABLE:以唯讀方式開啟檔案。
  • MODE_WORLD_WRITEABLE:以唯寫的方式開啟檔案。

  還有幾個方法需要特別注意一下,這幾個方法對於檔案關係提供了更好的支援,配合上面介紹的方式,就可以對檔案的資料進行常規的CRUD操作(增刪改查),方法如下:

  • File getFIlesDir():擷取檔案系統的絕對路徑。
  • boolean deleteFile(String name):刪除一個指定檔案名稱為name的檔案。
  • String[] fileList():當前應用內部儲存路徑下的所有檔案名稱。

   講了這麼多,下面通過一個簡單的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     <EditText13         android:id="@+id/etInternalFilename"14         android:layout_width="match_parent"15         android:layout_height="wrap_content" />16 17     <TextView18         android:layout_width="match_parent"19         android:layout_height="wrap_content"20         android:text="Content:" />21 22     <EditText23         android:id="@+id/etInternalContent"24         android:layout_width="match_parent"25         android:layout_height="wrap_content" />26 27     <LinearLayout28         android:layout_width="match_parent"29         android:layout_height="wrap_content"30         android:orientation="horizontal" >31 32         <Button33             android:id="@+id/btnInternalSave"34             android:layout_width="wrap_content"35             android:layout_height="wrap_content"36             android:text="save" />37 38         <Button39             android:id="@+id/btnInternalDelete"40             android:layout_width="wrap_content"41             android:layout_height="wrap_content"42             android:text="delete" />43 44         <Button45             android:id="@+id/btnInternalAppend"46             android:layout_width="wrap_content"47             android:layout_height="wrap_content"48             android:text="append" />49 50         <Button51             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     <ListView58         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     //需要儲存當前調用對象的Context16     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         @Override110         public void onItemClick(AdapterView<?> parent, View view, int position,111                 long id) {112             ListView lv = (ListView) parent;113             ArrayAdapter<String> adapter = (ArrayAdapter<String>) lv114                     .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 block125                 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,這個可以使用一個訪問裝置環境變數的類Environment進行判斷,這個類提供了一系列的靜態方法,用於擷取當前裝置的狀態,在這裡擷取是否存在有效Sdcard,使用的是Environment.getExternalStorageState()方法,返回的是一個字串資料,Environment封裝好了一些final對象進行匹配,除了Environment.MEDIA_MOUNTED外,其他均為有問題,所以只需要判斷是否是Environment.MEDIA_MOUNTED狀態即可。
  • 第二點,既然轉向了Sdcard,那麼儲存的檔案路徑就需要相對變更,這裡可以使用Envir.getExternalStorageDirectory()方法擷取當Sdcard的根目錄,可以通過它訪問到相應的檔案。
  • 第三點,需要賦予應用程式訪問Sdcard的許可權,Android的許可權控制尤為重點,在Android程式中,如果需要做一些越界的操作,均需要對其進行授權才可以訪問。在AndroidManifest.xml中添加代碼:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>   

  因為訪問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而言,需要修改路徑。

  源碼下載

 

總結

  以上就介紹了內部儲存、外部儲存、緩衝儲存的方式方法。開發人員可以根據需要選擇不同的方式進行資料持久化。

  請支援原創,尊重原創,轉載請註明出處。謝謝。

 

Android--資料持久化之內部儲存、Sdcard儲存

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.