前言
测试反馈如果断电前点击收藏歌曲(也就是拷贝到内置存储卡,有提示拷贝成功)后,开机起来后小概率出现部分收藏的歌曲消失了。
原因大概知道,但讲得不够清晰,因此看到网友文章,摘抄于此,方便自己查阅。
真正原因:拷贝文件是写入缓冲区内,调用的flush()也无法保证文件写入到了物理存储设备上。
PS: 本文内容基本摘抄的,感谢网友无私分享。
正文
拷贝代码可以参考《java.io.FileNotFoundException: /storage/** (No such file or directory)》中,这里就不重复了。
分析问题
Linux/Unix系统中,在文件或数据处理过程中一般先放到内存缓冲区中,等到适当的时候再写入磁盘,以提高系统的运行效率。
Android就是一个Linux系统
以下是文件拷贝流程示意图:
从上面写入文件后,是写入内核缓冲区,至于什么时候写入物理设备,我们是没办法知道的,除非自己主动调用fsync。
也就出现拷贝成功后马上断电导致文件丢失问题了。
解决问题
根据网友提示,解决方式有如下两种方式。
我实际项目中用的是方式一。
拷贝后主动sync
//将数据同步到达物理存储设备
FileDescriptor fd = fileOutputStream.getFD();
fd.sync();
inputStream.close();
fileOutputStream.close();
使用RandomAccessFile 的“rws”模式
/**
* 将asset/DB_NAME_CIYT 拷贝到指定目录
*
* @param databasePath
* @throws IOException
*/
private synchronized void copyDBFile(File databasePath) throws IOException {
String path = databasePath.getParentFile().getAbsolutePath() + "/";
Lg.e("dir = " + path);
File dir = new File(path);
if(!dir.exists()) dir.mkdirs();
databasePath.createNewFile();
InputStream inputStream = null;
RandomAccessFile randomAccessFile = null;
try {
inputStream = mContext.getAssets().open(DB_NAME_CIYT);
//rws模式,会同步到磁盘
randomAccessFile = new RandomAccessFile(databasePath,"rws");
byte[] buf = new byte[1024 * 10];
int lenth = 0;
Lg.e(TAG, "copyDBFile: startCopyDB");
while ((lenth = inputStream.read(buf)) != -1) {
randomAccessFile.write(buf, 0, lenth);
}
Lg.e(TAG, "copyDBFile: endCopyDB");
checkoutDB();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) inputStream.close();
if (randomAccessFile != null) randomAccessFile.close();
}
}
参考文章
历史上的今天
© 版权声明