Android設備如何保證數據同步寫入磁盤

在一些特定的工作場景中,我們把數據及時寫出磁盤,而不是暫時保存在系統的文件緩存區,防止掉電導致數據丟失

可能一看到這個場景,很多人會想到數據庫的事務,查看Android數據庫sqlite的源碼可以看到,數據庫事務只能保證n個操作,要麼都執行,要麼都不執行。數據庫事務在所有操作完成後,會提醒文件系統與磁盤同步,但是不會等到所有系統緩衝區與磁盤同步完成才返回!

可以查看sqlite官網對原子提交的說明 https://www.sqlite.org/atomiccommit.html#_incomplete_disk_flushes

在第二節的“硬件假設”裏面有這麼一段話

SQLite assumes that the operating system will buffer writes and that a write request will return before data has actually been stored in the mass storage device. SQLite further assumes that write operations will be reordered by the operating system. For this reason, SQLite does a "flush" or "fsync" operation at key points. SQLite assumes that the flush or fsync will not return until all pending write operations for the file that is being flushed have completed. We are told that the flush and fsync primitives are broken on some versions of Windows and Linux. This is unfortunate. It opens SQLite up to the possibility of database corruption following a power loss in the middle of a commit. However, there is nothing that SQLite can do to test for or remedy the situation. SQLite assumes that the operating system that it is running on works as advertised. If that is not quite the case, well then hopefully you will not lose power too often.

       大概意思是操作系統將緩衝寫操作,sqlite會在關鍵點執行“flush”或“fsync”操作。sqlite假設在正在刷新的文件的所有掛起寫入操作完成之前,刷新或fsync不會返回。我們被告知flush和fsync的功能在某些版本的windows和linux上被破壞。

如何解決這個問題呢?java給我們提供了一個接口!

/**
 * Force all system buffers to synchronize with the underlying
 * device.  This method returns after all modified data and
 * attributes of this FileDescriptor have been written to the
 * relevant device(s).  In particular, if this FileDescriptor
 * refers to a physical storage medium, such as a file in a file
 * system, sync will not return until all in-memory modified copies
 * of buffers associated with this FileDescriptor have been
 * written to the physical medium.
 *
 * sync is meant to be used by code that requires physical
 * storage (such as a file) to be in a known state  For
 * example, a class that provided a simple transaction facility
 * might use sync to ensure that all changes to a file caused
 * by a given transaction were recorded on a storage medium.
 *
 * sync only affects buffers downstream of this FileDescriptor.  If
 * any in-memory buffering is being done by the application (for
 * example, by a BufferedOutputStream object), those buffers must
 * be flushed into the FileDescriptor (for example, by invoking
 * OutputStream.flush) before that data will be affected by sync.
 *
 * @exception SyncFailedException
 *        Thrown when the buffers cannot be flushed,
 *        or because the system cannot guarantee that all the
 *        buffers have been synchronized with physical media.
 * @since     JDK1.1
 */
public native void sync() throws SyncFailedException;

 FileDescriptor.getFd().sync();會強制所有系統緩衝區與磁盤同步

File file = new File("/sdcard/a.txt");
        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write("kuangxf".getBytes());
            outputStream.flush();
            //強制文件系統刷新
            outputStream.getFD().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章