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();
        }

 

 

 

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