Android 寫文件時掉電丟失內容

原文鏈接:https://www.jianshu.com/p/9d529024fa3b

最近遇到了一個問題,做了一個檢測4G的模塊,檢測的結果是寫入到了sd卡中,如果有這個文件,下次再進來或者一鍵測試的時候就直接讀取這個文件就行。但是工廠的測試人員總是反饋檢測完沒有這個文件,然後我這麼怎麼試怎麼有。然後就很奇怪,就問了具體的測試流程,他們說只要檢測成功,就立馬掉電,然後換下一臺。我仔細檢查了代碼,沒毛病啊。這是怎麼了,flush() 和 close() 都有操作啊。
原先代碼是這樣的:

  String pathDir = Environment.getExternalStorageDirectory().getPath() + File.separator + "RFID";
        File dir = new File(pathDir);

        if (!dir.exists()) {
            dir.mkdir();
        }
        String fileName = "check4g_result";
        File fileVersion = new File(dir, fileName);
        try {
            FileOutputStream outSTr = new FileOutputStream(fileVersion);
            BufferedOutputStream buff = new BufferedOutputStream(outSTr);
            buff.write((result ? "true\r\n" : "false\r\n").getBytes());
            buff.flush();
            buff.close();
            log("寫入檢測4G結果成功");
        } catch (IOException e) {
            log("寫入檢測4G結果失敗");
        }

後來經過測試,確實是掉電引起的問題,那麼問題在哪呢?聽我一一分析。

1.關於flush()方法,api中有如下描述

刷新此輸出流並強制寫出所有緩衝的輸出字節。flush 的常規協定是:如果此輸出流的實現已經緩衝了以前寫入的任何字節,則調用此方法指示應將這些字節立即寫入它們預期的目標。
如果此流的預期目標是由基礎操作系統提供的一個抽象(如一個文件),則刷新此流只能保證將以前寫入到流的字節傳遞給操作系統進行寫入,但不保證能將這些字節實際寫入到物理設備(如磁盤驅動器)。

描述的最後一句話是重點但不保證能將這些字節實際寫入到物理設備(如磁盤驅動器) ,正如上面代碼,先創建一個文件,讓後向文件中寫入內容。其實Android底層在寫入文件的時候,其實現在磁盤上創建了這個文件,但是沒有立即寫入,只是寫入了緩存中,會在某個時機一次把所有內容寫入。所以我這個問題就出現在當寫入完之後掉電,內容還沒同步進去,此時已經掉電了。經過試驗,5s之後內容纔會同步到磁盤上。

那們怎麼解決呢?
這時調用sync方法強制同步一下。

2.FileDescriptor.sync()方法有如下描述

強制所有系統緩衝區與基礎設備同步。該方法在此 FileDescriptor 的所有修改數據和屬性都寫入相關設備後返回。特別是,如果此 FileDescriptor 引用物理存儲介質,比如文件系統中的文件,則一直要等到將與此 FileDesecriptor 有關的緩衝區的所有內存中修改副本寫入物理介質中,sync 方法纔會返回。 sync 方法由要求物理存儲(比例文件)處於某種已知狀態下的代碼使用。例如,提供簡單事務處理設施的類可以使用 sync 來確保某個文件所有由給定事務造成的更改都記錄在存儲介質上。 sync 隻影響此 FileDescriptor 的緩衝區下游。如果正通過應用程序(例如,通過一個 BufferedOutputStream 對象)實現內存緩衝,那麼必須在數據受 sync 影響之前將這些緩衝區刷新,並轉到 FileDescriptor 中(例如,通過調用 OutputStream.flush)。

修改之後的代碼:

 String pathDir = Environment.getExternalStorageDirectory().getPath() + File.separator + "RFID";
        File dir = new File(pathDir);

        if (!dir.exists()) {
            dir.mkdir();
        }
        String fileName = "check4g_result";
        File fileVersion = new File(dir, fileName);
        try {
            FileOutputStream outSTr = new FileOutputStream(fileVersion);
            BufferedOutputStream buff = new BufferedOutputStream(outSTr);
            buff.write((result ? "true\r\n" : "false\r\n").getBytes());
            buff.flush();
            outSTr.getFD().sync();//加入這行代碼可以解決這個問題
            buff.close();

            log("寫入檢測4G結果成功");
        } catch (IOException e) {
            log("寫入檢測4G結果失敗");
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章