Android 文件存儲

1.IO文件讀取

IO流類圖
IO流
分類

按照讀取數(shù)據(jù)類型不同分為字節(jié)流字符流
按照數(shù)據(jù)流向不同分為輸入流和```輸出流

常用方式
字節(jié)流FileInputStream 和 FileOutputStream文件讀寫
//寫入文件
 private void writeFile() {
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(path);
            String str = "asdasdadadad";
            outputStream.write(str.getBytes());
            outputStream.close();
        } 
       ...注意異常處理
    }
//讀取文件
FileInputStream inputStream = null;
try {
      inputStream = new FileInputStream(file);
      StringBuilder builder = new StringBuilder();
      int i = 0;
      while ((i = inputStream.read() )!= -1){
           builder.append((char)i);
       }
      //文件信息
      builder.toString()磅叛;
     inputStream.close();
}..異常處理
BufferedOutputStream與BufferedInputStream

BufferedInputStream是帶緩沖區(qū)的輸入流舞萄,默認(rèn)緩沖區(qū)大小是8M,能夠減少訪問磁盤的次數(shù)澎办,提高文件讀取性能捂敌;BufferedOutputStream是帶緩沖區(qū)的輸出流蟹演,能夠提高文件的寫入效率阴颖。BufferedInputStream與BufferedOutputStream分別是FilterInputStream類和FilterOutputStream類的子類愤诱,實(shí)現(xiàn)了裝飾設(shè)計(jì)模式云头。

FileOutputStream outputStream = null;
BufferedOutputStream bufferedOutputStream;
 try {
       outputStream = new FileOutputStream(path);
       bufferedOutputStream = new BufferedOutputStream(outputStream);
       String str = "sssssssasdafafasda";
       bufferedOutputStream.write(str.getBytes());
       //寫完畢后要將數(shù)據(jù)刷新到文件中
       bufferedOutputStream.flush();
       outputStream.close();
       bufferedOutputStream.close();
 } //異常處理
FileInputStream inputStream = null;
BufferedInputStream bufferedInputStream;
try {
      inputStream = new FileInputStream(file);
      bufferedInputStream = new BufferedInputStream(inputStream);
      StringBuilder builder = new StringBuilder();
      //緩沖區(qū) 不設(shè)置默認(rèn)為8K
      byte[] bytes = new byte[1024];
      int i = 0;
      while ((i = bufferedInputStream.read(bytes) )!= -1){
           builder.append(new String(bytes));
       }
      builder.toString()
      inputStream.close();
}//異常處理
字符流操作文件

FileWriterFileReader讀寫文件

    //寫文件
    private void writerFile() {
        FileWriter writer = null;
        try {
            writer = new FileWriter(path);
            String str = "中文測試呢";
            writer.write(str);
            writer.close();
        } //異常處理
    }
//讀文件
private void readerFile() {
        FileReader reader = null;
        try {
            reader = new FileReader(file);
            StringBuilder builder = new StringBuilder();
            int i = 0;
            while ((i = reader.read() )!= -1){
                builder.append((char)i);
            }
            mResult.setText(builder.toString());
            reader.close();
        } //異常處理
    }
BufferedReader和BufferedWriter,帶緩沖區(qū)的字符流淫半。
  private void bufferReaderFile() {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            StringBuilder builder = new StringBuilder();
            String str = "";
            while ((str = reader.readLine()) != null){
                builder.append(str);
            }
            mResult.setText(builder.toString());
            reader.close();
        } //異常處理
    }
    private void  bufferWriterFile() {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(path));
            String str = "BufferedWriter測試呢";
            writer.write(str);
            writer.close();
        } //異常處理
    }
InputStreamReader將字節(jié)流轉(zhuǎn)換為字符流
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "GB2312");
ObjectOutputStream與ObjectInputStream序列化與反序列化
    //序列化
    private void writeObject(){
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
            Student student = new Student();
            objectOutputStream.writeObject(student);
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (null != objectOutputStream){
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //反序列化
    private void readObject(){
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(path));
            Student student = (Student) objectInputStream.readObject();
            mResult.setText(student.toString());
            objectInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (null != objectInputStream){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
1.序列化 ID 問題

虛擬機(jī)是否允許反序列化溃槐,不僅取決于類路徑和功能代碼是否一致,一個(gè)非常重要的一點(diǎn)是兩個(gè)類的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)科吭。

2.靜態(tài)變量序列化

序列化保存的是對象的狀態(tài)昏滴,靜態(tài)變量屬于類的狀態(tài)猴鲫,因此 序列化并不保存靜態(tài)變量。

3.父類的序列化與 Transient 關(guān)鍵字

一個(gè)子類實(shí)現(xiàn)了 Serializable 接口谣殊,它的父類都沒有實(shí)現(xiàn) Serializable 接口拂共,序列化該子類對象,然后反序列化后輸出父類定義的某變量的數(shù)值姻几,該變量數(shù)值與序列化時(shí)的數(shù)值不同宜狐。
解決方法:要想將父類對象也序列化,就需要讓父類也實(shí)現(xiàn)Serializable 接口蛇捌「Ш悖或者有默認(rèn)的無參的構(gòu)造函數(shù),在構(gòu)造函數(shù)中完成初始化络拌。
Transient 關(guān)鍵字的作用是控制變量的序列化俭驮,在變量聲明前加上該關(guān)鍵字,可以阻止該變量被序列化到文件中春贸,在被反序列化后混萝,transient 變量的值被設(shè)為初始值,如 int 型的是 0萍恕,對象型的是 null逸嘀。

4.自定義序列化過程

虛擬機(jī)會試圖調(diào)用對象類里的 writeObject 和 readObject 方法,進(jìn)行用戶自定義的序列化和反序列化雄坪,如果沒有這樣的方法厘熟,則默認(rèn)調(diào)用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用戶自定義的 writeObject 和 readObject 方法可以允許用戶控制序列化的過程维哈。

   //序列化過程
    private void writeObject(ObjectOutputStream out) {
        try {
            ObjectOutputStream.PutField putFields = out.putFields();
            career = "new Student";//模擬加密
            putFields.put("career", career);
            out.writeFields();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   //反序列化過程
    private void readObject(ObjectInputStream in){
        try {
            ObjectInputStream.GetField getField = in.readFields();
            career = (String) getField.get("career", "");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
5.序列化存儲規(guī)則

Java 序列化機(jī)制為了節(jié)省磁盤空間绳姨,具有特定的存儲規(guī)則,當(dāng)寫入文件的為同一對象時(shí)阔挠,并不會再將對象的內(nèi)容進(jìn)行存儲飘庄,而只是再次存儲一份引用,新增一些控制信息购撼。反序列化時(shí)跪削,恢復(fù)引用關(guān)系該存儲規(guī)則極大的節(jié)省了存儲空間。

2.sqlite數(shù)據(jù)庫

sqlite數(shù)據(jù)庫的使用:
1迂求、繼承SQLiteOpenHelper

public class DbHelper extends SQLiteOpenHelper {

    //數(shù)據(jù)庫名稱
    private final static String dbName = "test.db";
    //表名稱
    public final static String dbTable = "testTable";

    public DbHelper(Context context){
        this(context,dbName,null,1);
    }

    public DbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        //上下文碾盐,數(shù)據(jù)庫名稱,游標(biāo)工廠揩局,版本號
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        //創(chuàng)建表操作
        String sql = "create table if not exists "+ dbTable+"(Id integer /*primary key*/ , Name text ,
 Price integer , Age integer)";
        sqLiteDatabase.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        //更新操作一般有如下步驟毫玖,本次演示只默認(rèn)刪除重建
        if (oldVersion != newVersion) {
            //1.創(chuàng)建臨時(shí)表保存數(shù)據(jù)
            //2.刪除現(xiàn)有表
            //3.創(chuàng)建新表
            //4.復(fù)制臨時(shí)表數(shù)據(jù)至新表
            //5.刪除臨時(shí)表
            sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + dbTable);
            onCreate(sqLiteDatabase);
        }
    }
}

2、創(chuàng)建數(shù)據(jù)庫操作類,持有SQLiteOpenHelper子類對象付枫,操作數(shù)據(jù)增刪改查:

   //插入
   public void insert(){
        SQLiteDatabase writableDatabase = mDbHelper.getWritableDatabase();
        writableDatabase.beginTransaction();
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (1,'xj2',12,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (2,'xj3',13,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (3,'xj4',14,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (4,'xj5',15,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (5,'xj6',16,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (6,'xj7',17,18)");
        writableDatabase.setTransactionSuccessful();
        writableDatabase.endTransaction();
    }
//查詢
public String  query(){
        SQLiteDatabase writableDatabase = mDbHelper.getWritableDatabase();
        Cursor query = writableDatabase.query(mDbHelper.dbTable, null, null, null, null, null, null);
        StringBuilder builder = new StringBuilder();
        while (query.moveToNext()){
           //查詢數(shù)據(jù)
           int id = query.getInt(query.getColumnIndex("Id"));
        }
        return builder.toString();
    }
其余方法等同.數(shù)據(jù)庫詳細(xì)語法后續(xù)再詳細(xì)學(xué)習(xí)烹玉。

數(shù)據(jù)庫操作有兩種方式,一種如insert方法一樣執(zhí)行SQL語句阐滩,另一種如query方法一樣使用SQLiteDatabase 封裝過的方法二打。
sqlite是線程安全的嗎
Android中SQLiteDatabase為sqlite提供了線程安全的保證,因此Android中sqlite數(shù)據(jù)庫是線程安全的掂榔。
sqlite是線程安全的嗎
數(shù)據(jù)庫保存在/data/data/pageName/databases/dbName.db继效,其中pageName為包名,dbName為數(shù)據(jù)庫名稱衅疙。

3.SharedPreferences

SharedPreferences是Android輕量級的存儲方式莲趣,使用方式如下

    public void saveSp(){
        SharedPreferences preferences = getSharedPreferences("perfer_file",MODE_PRIVATE);
        SharedPreferences.Editor edit = preferences.edit();
        edit.putString("key",value);
        edit.putInt("key",value);
        ....
        edit.apply();/edit.commit();
    }

    public void readSp(){
        SharedPreferences preferences = getSharedPreferences("xujie,",MODE_PRIVATE);
        String value= preferences.getString("key", defaultValue);
        int value= preferences.getInt("key", defaultValue);
        ...
    }

存取使用SharedPreferences.Editor來完成鸳慈。數(shù)據(jù)存儲在/data/data/pageName/shared_prefs/perfer_file.xml里面饱溢,結(jié)構(gòu)如下:

<map>
    <string name="key">value</string>
    <int name="key" value="value" />
</map>

注意點(diǎn):
1.SharedPreferences對大小沒有限制,但是如果存儲數(shù)據(jù)過大會導(dǎo)致性能問題走芋,因此要存儲合理的數(shù)據(jù)绩郎。
2.SharedPreferences只能存儲基本類型的數(shù)據(jù)。
3.SharedPreferences線程不安全翁逞。

4.ContentProvider

四大組件之一肋杖,數(shù)據(jù)通過ContentProvider存儲在別的工程中⊥诤可參考四大組件文章状植。

5.網(wǎng)絡(luò)存儲

數(shù)據(jù)存儲在網(wǎng)絡(luò)上,通過Http等協(xié)議獲取數(shù)據(jù)怨喘,常用庫為Okhttp等津畸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市必怜,隨后出現(xiàn)的幾起案子肉拓,更是在濱河造成了極大的恐慌,老刑警劉巖梳庆,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暖途,死亡現(xiàn)場離奇詭異,居然都是意外死亡膏执,警方通過查閱死者的電腦和手機(jī)驻售,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來更米,“玉大人欺栗,你說我怎么就攤上這事。” “怎么了纸巷?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵镇草,是天一觀的道長。 經(jīng)常有香客問我瘤旨,道長梯啤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任存哲,我火速辦了婚禮因宇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祟偷。我一直安慰自己察滑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布修肠。 她就那樣靜靜地躺著贺辰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嵌施。 梳的紋絲不亂的頭發(fā)上饲化,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音吗伤,去河邊找鬼吃靠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛足淆,可吹牛的內(nèi)容都是我干的巢块。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼巧号,長吁一口氣:“原來是場噩夢啊……” “哼族奢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起裂逐,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤歹鱼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后卜高,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弥姻,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年掺涛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庭敦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡薪缆,死狀恐怖秧廉,靈堂內(nèi)的尸體忽然破棺而出伞广,到底是詐尸還是另有隱情,我是刑警寧澤疼电,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布嚼锄,位于F島的核電站,受9級特大地震影響蔽豺,放射性物質(zhì)發(fā)生泄漏区丑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一修陡、第九天 我趴在偏房一處隱蔽的房頂上張望沧侥。 院中可真熱鬧,春花似錦魄鸦、人聲如沸宴杀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旺罢。三九已至,卻和暖如春盾致,著一層夾襖步出監(jiān)牢的瞬間主经,已是汗流浹背荣暮。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工庭惜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人穗酥。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓护赊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砾跃。 傳聞我的和親對象是個(gè)殘疾皇子骏啰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

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