標籤:

在 Android 中有哪幾種數據存儲方式?


就我所知:

1.File I/O

2.SQLite

3.Preferences

4.Content provider

5.網路存儲


JetZ的回答比較全。

我想推薦File I/O的一種, 也是java中的方式---對象序列化。 這種方法可以將對象序列化到緩存中,下次讀取就只需反序列化就好了, 速度也很快。

SQLite資料庫讀取速度還可以, 不過寫入速度是相當慢,對程序性能影響很大,使用的時候要注意。

ContentProvider 是android的數據存儲的標準介面, 若是對資料庫操作最好在數據的基礎上封裝一層ContentProvider。

補充一下:

之所以推薦用ContnetProvider是因為在activity中資料庫的關閉問題。若是在onResume打開,onPause里關閉,你就會發現每次進入這個activity就要載入一次資料庫數據,效率上和體驗上都不好;若是在onCreate里打開,onDestroy裡面關閉,你會在logcat里得到出錯的提示,find leak... 說明資料庫沒有正常關閉。

而如果用contentprovider可以有效的避免這個問題, 資料庫打開和關閉都不用操心了。

不過,ContentProver的代碼寫起來比較痛苦,很多人都不喜歡用,因為要照顧到一個協議,雖然是用Uri實現的協議l,而且要是比較高級的查詢也比較麻煩。

這裡, 我推薦一種比較另類的解決方案:

重載程序的Application,在它的onCreate裡面打開資料庫,在onDestroy裡面關閉資料庫,提供一個獲取數據實例的介面,就可以解決上面提到的問題了。


@JetZ 的答案中,Content Provider不能算是一種數據存儲方式。它只是給我們提供操作數據的介面,Content Provider背後其實還是SQLite、File IO等其他方式。

所以在官方文檔中,指出的存儲方式也只有四種(SD卡內外存儲算一種):

Your data storage options are the following:

Shared PreferencesStore private primitive data in key-value pairs.

Internal StorageStore private data on the device memory.

External StorageStore public data on the shared external storage.

SQLite DatabasesStore structured data in a private database.

Network ConnectionStore data on the web with your own network server.

Android provides a way for you to expose even your private data to other applications — with a content provider. A content provider is an optional component that exposes read/write access to your application data, subject to whatever restrictions you want to impose. For more information about using content providers, see the Content Providers documentation.

via:

Storage Options


Android 使用與其他平台上基於磁碟的文件系統類似的文件系統。

本文講述如何使用 Android 文件系統通過 File API 讀取和寫入文件。

File 對象適合按照從開始到結束的順序不跳過地讀取或寫入大量數據。 例如,它適合於圖片文件或通過網路交換的任何內容。

本文展示如何在您的應用中執行基本的文件相關任務。

假定您熟悉 Linux 文件系統的基礎知識和 http://java.io 中的標準文件輸入/輸出 API。

選擇內部或外部存儲

所有 Android 設備都有兩個文件存儲區域:「內部」和「外部」存儲。這些名稱在 Android 早期產生,當時大多數設備都提供內置的非易失性內存(內部存儲),以及移動存儲介質,比如微型 SD 卡(外部存儲)。一些設備將永久性存儲空間劃分為「內部」和「外部」分區,即便沒有移動存儲介質,也始終有兩個存儲空間,並且無論外部存儲設備是否可移動,API 的行為均一致。以下列表匯總了關於各個存儲空間的實際信息。

內部存儲:

它始終可用。

只有您的應用可以訪問此處保存的文件。

當用戶卸載您的應用時,系統會從內部存儲中移除您的應用的所有文件。

當您希望確保用戶或其他應用均無法訪問您的文件時,內部存儲是最佳選擇。

外部存儲:

它並非始終可用,因為用戶可採用 USB 存儲設備的形式裝載外部存儲,並在某些情況下會從設備中將其移除。

它是全局可讀的,因此此處保存的文件可能不受您控制地被讀取。

當用戶卸載您的應用時,只有在您通過 getExternalFilesDir() 將您的應用的文件保存在目錄中時,系統才會從此處移除您的應用的文件。

對於無需訪問限制以及您希望與其他應用共享或允許用戶使用計算機訪問的文件,外部存儲是最佳位置。

註:

在 Android N 之前,內部文件可以通過放寬文件系統許可權讓其他應用訪問。而如今不再是這種情況。如果您希望讓其他應用訪問私有文件的內容,則您的應用可使用 FileProvider。

提示:

儘管應用默認安裝在內部存儲中,但您可在您的清單文件中指定 android:installLocation 屬性,這樣您的應用便可安裝在在外部存儲中。當 APK 非常大且它們的外部存儲空間大於內部存儲時,用戶更青睞這個選擇。 如需了解詳細信息,請參閱應用安裝位置。

獲取外部存儲的許可權

要向外部存儲寫入信息,您必須在您的清單文件中請求 WRITE_EXTERNAL_STORAGE 許可權。

注意:

目前,所有應用都可以讀取外部存儲,而無需特別的許可權。 但這在將來版本中會進行更改。如果您的應用需要讀取外部存儲(但不向其寫入信息),那麼您將需要聲明 READ_EXTERNAL_STORAGE 許可權。要確保您的應用繼續正常工作,您應在更改生效前聲明此許可權。

將文件保存在內部存儲中

在內部存儲中保存文件時,您可以通過調用以下兩種方法之一獲取作為 File 的相應目錄:

1.getFilesDir()

返回表示您的應用的內部目錄的 File 。

2.getCacheDir()

返回表示您的應用臨時緩存文件的內部目錄的 File。 務必刪除所有不再需要的文件並對在指定時間您使用的內存量實現合理大小限制,比如,1MB。 如果在系統即將耗盡存儲,它會在不進行警告的情況下刪除您的緩存文件。

要在這些目錄之一中新建文件

1.您可以使用 File() 構造函數,傳遞指定您的內部存儲目錄的上述方法之一所提供的 File。例如:

File file = new File(context.getFilesDir(), filename);

2.或者,您可以調用 openFileOutput() 獲取寫入到內部目錄中的文件的 FileOutputStream。例如,下面顯示如何向文件寫入一些文本:

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

3.或者,如果您需要緩存某些文件,您應改用 createTempFile()。例如,以下方法從 URL 提取文件名並正在您的應用的內部緩存目錄中以該名稱創建文件:

public File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null, context.getCacheDir());
} catch (IOException e) {
// Error while creating file
}
return file;
}

註:您的應用的內部存儲設備目錄由您的應用在 Android 文件系統特定位置中的軟體包名稱指定。從技術上講,如果您將文件模式設置為可讀,那麼,另一應用也可以讀取您的內部文件。 但是,此應用也需要知道您的應用的軟體包名稱和文件名。 其他應用無法瀏覽您的內部目錄並且沒有讀寫許可權,除非您明確將文件設置為可讀或可寫。 只要您為內部存儲上的文件使用 MODE_PRIVATE,其他應用便從不會訪問它們。

將文件保存在外部存儲中

由於外部存儲可能不可用—比如,當用戶已將存儲裝載到電腦或已移除提供外部存儲的 SD 卡時—因此,在訪問它之前,您應始終確認其容量。 您可以通過調用 getExternalStorageState() 查詢外部存儲狀態。 如果返回的狀態為 MEDIA_MOUNTED,那麼您可以對您的文件進行讀寫。 例如,以下方法對於確定存儲可用性非常有用:

/

* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}

儘管外部存儲可被用戶和其他應用進行修改,但您可在此處保存兩類文件:公共文件

應供其他應用和用戶自由使用的文件。 當用戶卸載您的應用時,用戶應仍可以使用這些文件。

例如,您的應用拍攝的照片或其他已下載的文件。

私有文件

屬於您的應用且在用戶卸載您的應用時應予刪除的文件。 儘管這些文件在技術上可被用戶和其他應用訪問(因為它們存儲在外部存儲中), 但它們實際上不向您的應用之外的用戶提供任何輸出值。 當用戶卸載您的應用時,系統會刪除應用外部私有目錄中的所有文件。

例如,您的應用下載的其他資源或臨時介質文件。

如果您要將公共文件保存在外部存儲設備上,請使用 getExternalStoragePublicDirectory() 方法獲取表示外部存儲設備上相應目錄的 File。 該方法使用指定您想要保存以便它們可以與其他公共文件在邏輯上組織在一起的文件類型的參數,比如 DIRECTORY_MUSIC 或 DIRECTORY_PICTURES。例如:

public File getAlbumStorageDir(String albumName) {

// Get the directory for the user』s public pictures directory.

File file = new File(Environment.getExternalStoragePublicDirectory(

Environment.DIRECTORY_PICTURES), albumName);

if (!file.mkdirs()) {

Log.e(LOG_TAG, 「Directory not created」);

}

return file;

}

如果您要保存您的應用專用文件,您可以通過調用 getExternalFilesDir() 並向其傳遞指示您想要的目錄類型的名稱,從而獲取相應的目錄。通過這種方法創建的各個目錄將添加至封裝您的應用的所有外部存儲文件的父目錄,當用戶卸載您的應用時,系統會刪除這些文件。

例如,您可以使用以下方法來創建個人相冊的目錄:

public File getAlbumStorageDir(Context context, String albumName) {

// Get the directory for the app』s private pictures directory.

File file = new File(context.getExternalFilesDir(

Environment.DIRECTORY_PICTURES), albumName);

if (!file.mkdirs()) {

Log.e(LOG_TAG, 「Directory not created」);

}

return file;

}

如果沒有適合您文件的預定義子目錄名稱,您可以改為調用 getExternalFilesDir() 並傳遞 null。這將返回外部存儲上您的應用的專用目錄的根目錄。

切記,getExternalFilesDir() 在用戶卸載您的應用時刪除的目錄內創建目錄。如果您正保存的文件應在用戶卸載您的應用後仍然可用—比如,當您的應用是照相機並且用戶要保留照片時—您應改用 getExternalStoragePublicDirectory()。

無論您對於共享的文件使用 {@linkandroid.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()} 還是對您的應用專用文件使用 getExternalFilesDir(),您使用諸如 DIRECTORY_PICTURES 的 API 常數提供的目錄名稱非常重要。這些目錄名稱可確保系統正確處理文件。 例如,保存在 DIRECTORY_RINGTONES 中的文件由系統媒體掃描程序歸類為鈴聲,而不是音樂。

查詢可用空間

如果您事先知道您將保存的數據量,您可以查出是否有足夠的可用空間,而無需調用 getFreeSpace() 或 getTotalSpace() 引起 IOException。這些方法分別提供目前的可用空間和存儲卷中的總空間。 此信息也可用來避免填充存儲卷以致超出特定閾值。

但是,系統並不保證您可以寫入與 getFreeSpace() 指示的一樣多的位元組。如果返回的數字比您要保存的數據大小大出幾 MB,或如果文件系統所佔空間不到 90%,則可安全繼續操作。否則,您可能不應寫入存儲。

註:保存您的文件之前,您無需檢查可用空間量。 您可以嘗試立刻寫入文件,然後在 IOException 出現時將其捕獲。 如果您不知道所需的確切空間量,您可能需要這樣做。 例如,如果在保存文件之前通過將 PNG 圖像轉換成 JPEG 更改了文件的編碼,您事先將不知道文件的大小。

刪除文件

您應始終刪除不再需要的文件。刪除文件最直接的方法是讓打開的文件參考自行調用 delete()。

myFile.delete();

如果文件保存在內部存儲中,您還可以請求 Context 通過調用 deleteFile() 來定位和刪除文件:

myContext.deleteFile(fileName);

註:當用戶卸載您的應用時,Android 系統會刪除以下各項:

您保存在內部存儲中的所有文件

您使用 getExternalFilesDir() 保存在外部存儲中的所有文件。

但是,您應手動刪除使用 getCacheDir() 定期創建的所有緩存文件並且定期刪除不再需要的其他文件。】

我的微信二維碼如下

http://weixin.qq.com/r/W4317brEb_cQrf6O99hJ (二維碼自動識別)

歡迎關注《IT面試題匯總》微信訂閱號。

http://weixin.qq.com/r/dztQSJTE9cmKrdAr925l (二維碼自動識別)


推薦閱讀:

數據資源獲取方式匯總一下?在哪找數據/數據交易平台/數據api介面?
如何讓excel的多個文件里的數據自動篩選對比形成一個固定格式的報表?
年輕家庭適合去南京、上海還是蘇州打拚生活?
1mb(毫比特)的數據有多大?
在處理時間序列數據的時候有哪些大幅提高效率的方法或技術?

TAG:數據 | Android |