Android數(shù)據(jù)存儲方式以及SharedPreferences和存儲系統(tǒng)使用方法

在android平臺中,數(shù)據(jù)存儲一共有5種方式:

  • SharedPreference
  • ** 文件**
  • SQLite數(shù)據(jù)庫
  • ContentProvider
  • 網(wǎng)絡(luò)

接下來依次介紹一下各種存儲方式柱宦。

SharedPreferences

SharedPreference可以用來保存任何原始數(shù)據(jù):布爾值踩身、浮點值别凹、整型值、長整型和字符串,它存儲的數(shù)據(jù)以鍵值對的形式挤牛,生成一個xml文件,存放在/data/data/<package name>/shared_prefs路徑下种蘸。
獲取SharedPreferences對象通常有兩種方法:

  • getSharedPreferences()
    此方法包含另個參數(shù)墓赴,第一個是文件名,第二個是mode航瞭。采用該方法生成的SharedPreferences文件诫硕,是整個應(yīng)用所共享的,可以在同一應(yīng)用的任意Context下讀寫刊侯。它是屬于Context類的

  • getPreferences()
    此方法只有一個參數(shù)章办,mode。它所生成的文件滨彻,用包名+類名的方式來命名藕届,比如應(yīng)用包為com.example.app,生成該文件的類是位于preferences包下的MyPreferenceActivity類亭饵,那么它的路徑如下:
    /data/data/com.example.app/shares_prefs/preferences.MyPreferenceActivity.xml
    它適用于只在當(dāng)前Activity調(diào)用的sharedPreferences休偶,是屬于Activity類的。

除了以上兩種方法之外辜羊,還有一種方法:
PreferenceManager.getDefaultSharedPreferences(Context context);

這樣獲取到的對象是應(yīng)用默認(rèn)的Preference文件踏兜,它的名字是該應(yīng)用的完整包名+_preferences。比如應(yīng)用包為com.example.app八秃,生成該文件的類是位于preferences包下的MyPreferenceActivity類庇麦,那么它的路徑如下:
/data/data/com.example.app/shares_prefs/com.example.app_preferences.xml

SharedPreferences的mode參數(shù)

剛才提到的參數(shù)mode喜德,有以下值可選:

  • Context.MODE_PRIVATE
    SharedPreferences數(shù)據(jù)只能被本應(yīng)用程序讀山橄、寫。

  • Context.MODE_APPEND 寫入數(shù)據(jù)采用append方式舍悯。

  • Context.MODE_WORLD_READABLE
    SharedPreferences數(shù)據(jù)能被其他應(yīng)用程序讀航棱,但不能寫。4.2之后已棄用萌衬。

  • Context.MODE_WORLD_WRITEABLE
    SharedPreferences數(shù)據(jù)能被其他應(yīng)用程序讀和寫饮醇。4.2之后已棄用。

  • Context.MODE_MULTI_PROCESS
    sdk2.3后添加的選項秕豫,當(dāng)多個進(jìn)程同時讀寫同一個SharedPreferences時它會檢查文件是否修改朴艰。6.0中已棄用

所以观蓄,通常情況下我們選MODE_PRIVATE就可以了,也可以直接寫0祠墅,就是MODE_PRIVATE侮穿。只有在跨進(jìn)程訪問SharedPreferences時,才會選用MODE_MULTI_PROCESS毁嗦。其實MODE_PRIVATE也可以跨進(jìn)程訪問亲茅,但是讀取到的數(shù)據(jù)是不會更新的,一直都是初始數(shù)據(jù)狗准。

在獲取到SharedPreferences對象以后克锣,就可以修改存儲數(shù)據(jù)了。需要注意的是腔长,SharedPreferences對象本身并不對數(shù)據(jù)進(jìn)行修改袭祟,而是通過Editor來進(jìn)行操作的,修改完成以后調(diào)用editor.commit來提交捞附。下面看具體代碼:

SharedPreferences sp;
SharedPreferences preferences;
SharedPreferences defautSp;
@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.data_storage);
    sp=getSharedPreferences("preferences_1", MODE_PRIVATE);
    preferences=getPreferences(MODE_PRIVATE);
    defautSp=PreferenceManager.getDefaultSharedPreferences(this);
    Editor editor = sp.edit();
    editor.putString("name", "你大爺");
    editor.commit();
    //讀取數(shù)據(jù)榕酒,第二個參數(shù)是讀取失敗時返回的值
    String name = sp.getString("name", "");

注意:SharedPreferences文件默認(rèn)為private模式,editor中的內(nèi)容就是文件中將要存儲的內(nèi)容故俐,新的editor提交以后,文件中存儲的就是剛提交的editor中的數(shù)據(jù)紊婉,之前的所有數(shù)據(jù)都會被覆蓋掉. 可以在創(chuàng)建對象時指定模式為APPEND

不同應(yīng)用之間訪問SharedPreference:

因為SharedPreferences是與Context相關(guān)的药版,想訪問其他應(yīng)用的SharedPreferences,第一步應(yīng)該拿到目標(biāo)應(yīng)用的Context喻犁,代碼如下:

Context trainContext=createPackageContext("com.example.app", Context.CONTEXT_IGNORE_SECURITY);

然后就可以用Context.getSharedPreferences("file_name",MODE_MULTI_PROCESS)來獲取SharedPreferences對象槽片。

還有關(guān)鍵的一步,跨應(yīng)用共享數(shù)據(jù)的時候肢础,需要在共享數(shù)據(jù)的應(yīng)用里中定義相同的SharedUserId屬性:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.training"
    android:versionCode="1"
    android:versionName="1.0" 
    android:sharedUserId="com.share"
    >

這樣还栓,就可以在不同的應(yīng)用中共享數(shù)據(jù)了。

除此之外传轰,還可以用文件的方式剩盒,直接通過路徑來讀取xml文件:
File xmlFile = new File(“/data/data/.../shared_prefs/config.xml”)

文件存儲

在Android中,可以使用下面兩種方法慨蛙,來存儲和讀取文件:
FileInputStream openFileInput(String name);
FileOutputStream openFileOutput(String name , int mode);

使用這種方式保存到內(nèi)部存儲的文件是應(yīng)用的私有文件辽聊,存儲路徑為/data/data/<package name>/files目錄,如: /data/data/com.example.app/files/message.txt,其他應(yīng)用是不能訪問這些數(shù)據(jù)的期贫。
示例代碼如下:
存儲:

try {
    FileOutputStream fos = openFileOutput("file_1", MODE_PRIVATE);
    fos.write("This is file storage.".getBytes());
    fos.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

讀取文件:

try {
    FileInputStream fis = openFileInput("file_1");
    StringBuilder sb = new StringBuilder();
     int length=-1;
    byte[] buffer = new byte[1024];
    while ((length = fis.read(buffer)) != -1) {
    //sb.append(new String(buffer,0,length);
    sb.append(EncodingUtils.getString(buffer,0,length, "UTF-8"));
    }
    fis.close();
    Log.d("Storage", "File content: "+sb.toString());
                
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

在輸出文件的時候跟匆,openFileOutput也有一個mode,官方文檔是這么說的:

MODE_PRIVATE
將會創(chuàng)建文件(或替換具有相同名稱的文件)通砍,并將其設(shè)為應(yīng)用的私有文件玛臂。 其他可用模式包括:MODE_APPENDMODE_WORLD_READABLEMODE_WORLD_WRITEABLE

:自 API 級別 17 以來迹冤,常量 MODE_WORLD_READABLEMODE_WORLD_WRITEABLE 已被棄用讽营。從 Android N 開始,使用這些常量將會導(dǎo)致引發(fā) SecurityException叁巨。這意味著斑匪,面向 Android N 和更高版本的應(yīng)用無法按名稱共享私有文件,嘗試共享“file://”URI 將會導(dǎo)致引發(fā)FileUriExposedException锋勺。 如果您的應(yīng)用需要與其他應(yīng)用共享私有文件蚀瘸,則可以將 FileProvider
FLAG_GRANT_READ_URI_PERMISSION 配合使用。另請參閱共享文件庶橱。

Android的文件存儲系統(tǒng)

首先贮勃,可以看一下這篇博客,這里詳細(xì)的介紹了安卓的內(nèi)部存儲和外部存儲的區(qū)別。

內(nèi)部存儲

存放在/data/data/pacakge路徑下苏章,SharedPreferences寂嘉,SQLite數(shù)據(jù)庫,還有文件存儲枫绅,都是放在這個目錄下的泉孩,成為應(yīng)用的內(nèi)部存儲。對應(yīng)用的內(nèi)部存儲進(jìn)行操作并淋,除了上邊介紹的兩個方法之外寓搬,還有以下常用方法:

  • getFilesDir()
    獲取在其中存儲內(nèi)部文件的文件系統(tǒng)目錄的絕對路徑。即:/data/data/pacakge/flies

  • getDir(String name, int mode)
    在您的內(nèi)部存儲空間內(nèi)創(chuàng)建(或打開現(xiàn)有的)目錄县耽。如果沒有句喷,會創(chuàng)建一個 app_name 文件夾,返回的路徑是/data/data/pacakge/app_name

  • deleteFile(String name)
    刪除保存在內(nèi)部存儲(files文件夾)的文件。

  • fileList()
    返回應(yīng)用當(dāng)前保存的一系列文件(files文件夾下的文件列表)

除此之外兔毙,還有一個保存緩存文件的方法:
getCacheDir()
它表示您的應(yīng)用應(yīng)該將臨時緩存文件保存到的內(nèi)部目錄唾琼,獲取到的是/data/data/pacakge/cache目錄.

關(guān)于緩存文件,Android是這么說的:

當(dāng)設(shè)備的內(nèi)部存儲空間不足時澎剥,Android 可能會刪除這些緩存文件以回收空間锡溯。 但您不應(yīng)該依賴系統(tǒng)來為您清理這些文件, 而應(yīng)該始終自行維護(hù)緩存文件哑姚,使其占用的空間保持在合理的限制范圍內(nèi)(例如 1 MB)趾唱。

內(nèi)部存儲的所有文件在用戶卸載應(yīng)用時,這些文件也會被移除蜻懦。

外部存儲

與內(nèi)部存儲相對的甜癞,外部存儲可以是SD卡,擴(kuò)展的u盤宛乃,系統(tǒng)自帶的內(nèi)部存儲卡等等念秧,它的特點是,所有的文件是全局都可以訪問的阅爽,而內(nèi)部存儲通常是應(yīng)用私有的(可以通過context來訪問)茬斧。
要操作外部存儲之前蜗搔,首先要獲得訪問權(quán)限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

如果需要讀取和寫入文件,則只需請求 WRITE_EXTERNAL_STORAGE權(quán)限,因為此權(quán)限也隱含了讀取權(quán)限要求。

Android中的外部存儲拂玻,又可以分為兩個部分,一是可以與其他應(yīng)用共享的公共文件宰译,比如 Music/檐蚜、Pictures/Ringtones/

另一部分則是私有文件,這里私有文件的定義不是說其他的應(yīng)用不可以訪問沿侈,而是對其他應(yīng)用沒有訪問價值闯第,應(yīng)用卸載之后,私有文件也會隨之刪除缀拭,而公共文件會被保留下來咳短。

  1. 公共文件:路徑是/storage/sdcard

常用方法:

  • Environment.getExternalStorageDirectory()
  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)//獲取系統(tǒng)的照片文件路徑

比如要在DCIM文件夾下創(chuàng)建一個新的文件夾

File newfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "myPicture");
if (!newfile.mkdirs()) {
  Log.e("Storage", "Directory not created");
}
  1. 外部私有文件:路徑是/storage/sdcard/Android/data/packagename/files

外部私有文件的操作是屬于Context類的,主要有以下常用方法:

  • File getExternalFilesDir()
  • File[] getExternalFilesDirs()
  • File getExternalCacheDir()
  • File[] getExternalCacheDirs()
  • File[] getExternalMediaDirs()

例如蛛淋,要創(chuàng)建一個ext_private_file文件夾:

  File newfile2 = new File(this.getExternalFilesDir("ext_private"), "myPicture");
                 if (!newfile2.mkdirs()) {
                        Log.e("Storage", "Directory not created");
                    }

這個文件存儲的位置并不是sd卡的根目錄下的ext_private文件夾咙好,Android會為外部的私有存儲新建一個目錄,例如:/storage/sdcard/Android/data/<package_name>/files/褐荷。其他的應(yīng)用也可以訪問這個目錄勾效,但是,存放在此處的內(nèi)容通常是對其他應(yīng)用沒有訪問價值诚卸。

與外部公共文件相比,私有文件在應(yīng)用卸載的時候绘迁,會隨之一起刪除合溺,而使用Environment內(nèi)的操作方法創(chuàng)建的公共文件并不會隨之卸載。

在API19 Android4.4以后缀台,操作外部的私有存儲并不需要申請讀寫權(quán)限了棠赛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市膛腐,隨后出現(xiàn)的幾起案子睛约,更是在濱河造成了極大的恐慌,老刑警劉巖哲身,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辩涝,死亡現(xiàn)場離奇詭異,居然都是意外死亡勘天,警方通過查閱死者的電腦和手機(jī)怔揩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門捉邢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人商膊,你說我怎么就攤上這事伏伐。” “怎么了晕拆?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵藐翎,是天一觀的道長。 經(jīng)常有香客問我实幕,道長吝镣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任茬缩,我火速辦了婚禮赤惊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凰锡。我一直安慰自己未舟,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布掂为。 她就那樣靜靜地躺著裕膀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勇哗。 梳的紋絲不亂的頭發(fā)上昼扛,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音欲诺,去河邊找鬼抄谐。 笑死,一個胖子當(dāng)著我的面吹牛扰法,可吹牛的內(nèi)容都是我干的蛹含。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼塞颁,長吁一口氣:“原來是場噩夢啊……” “哼浦箱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起祠锣,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤酷窥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伴网,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蓬推,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年澡腾,在試婚紗的時候發(fā)現(xiàn)自己被綠了拳氢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片募逞。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖馋评,靈堂內(nèi)的尸體忽然破棺而出放接,到底是詐尸還是另有隱情,我是刑警寧澤留特,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布纠脾,位于F島的核電站,受9級特大地震影響蜕青,放射性物質(zhì)發(fā)生泄漏苟蹈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一右核、第九天 我趴在偏房一處隱蔽的房頂上張望慧脱。 院中可真熱鬧,春花似錦贺喝、人聲如沸菱鸥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氮采。三九已至,卻和暖如春染苛,著一層夾襖步出監(jiān)牢的瞬間鹊漠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工茶行, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留躯概,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓畔师,卻偏偏與公主長得像娶靡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子茉唉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容