前言

测试反馈如果断电前点击收藏歌曲(也就是拷贝到内置存储卡,有提示拷贝成功)后,开机起来后小概率出现部分收藏的歌曲消失了。

原因大概知道,但讲得不够清晰,因此看到网友文章,摘抄于此,方便自己查阅。

真正原因:拷贝文件是写入缓冲区内,调用的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();
    }
}

参考文章

  1. 拷贝文件时,做完MD5校验,异常断电导致文件拷贝失败

相关文章

暂无评论

none
暂无评论...