安卓设备内部文件操作可以使用Android文件操作帮助类FileUtils
注意:
安卓设备若是外接OTG,向外部存储进行文件操作时有时会出现异常。排除权限原因,文件在向OTG进行文件复制粘贴或是删除时,当函数返回成功时,文件有时并未实际写入磁盘,现象就是:向外部设备复制一个文件,当提示文件复制成功时立即拔出OTG,再插上OTG发现刚复制成功的文件损坏,排除Android对OTG热插拔的支持问题。
热插拔OTG,导致刚复制的文件损坏的原因是:文件复制是有缓冲机制的,函数返回复制成功时,文件并未实际落入磁盘,感觉flush()/sync()并未起作用。
解决方法:
- 方法1.拔掉OTG,要求安全卸载外部存储设备,执行StorageManager . unmount();
- 方法2.使用NDK方式编译so,采用Linux open write 文件写入选择绕过缓冲区 直接写入。此种方法缺点:速度会慢很多,如果有大文件的复制操作(超过500M),等待时间会难以忍受。
src = open(srcPath, O_RDONLY | O_EXCL);
dst= open(dstPath, O_RDWR | O_CREAT | O_SYNC | O_DIRECT);
//源文件设置只读模式,若设置读写模式会导致:正在写的文件无法复制。
flag用于指定文件的打开/创建模式,这3个常量定义在fcntl.h中,这3个参数是必选的,而且只能选择一个:
O_RDONLY 只读模式
O_WRONLY 只写模式
O_RDWR 读写模式
下面的常量是可选的:
O_DIRECT: 无缓冲的输入、输出。
O_APPEND 每次写操作都写入文件的末尾。
O_CREAT 如果指定文件不存在,则创建这个文件。如果存在则直接打开文件。如果创建新文件,而mode参数没有指定,则创建的文件权限不定。
O_EXCL 如果文件不存在,则返回错误。如果同时指定了O_CREAT,而文件已经存在,则会出错。 用此测试一个文件是否存在,如果不存在,则创建此文件。
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容。
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)。
下面三个标志也是可选的,他们是Single UNIX Specification中同步输入和输出选项的一部分:
O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
O_RSYNC read 等待所有写入同一区域的写操作完成后再进行。
O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O,以同步IO方式打开文件。
使用Android代码进行文件复制需要注意的几点:
- 文件复制结束后需要关闭文件流
- 文件复制结束后需要flush()
- 文件复制结束后需要out.getFD().sync();
以下是FileUtils中部分代码。
/**
* Copy data from a source stream to destFile.
* Return true if succeed, return false if failed.
*/
public static boolean copyToFile(InputStream inputStream, File destFile) {
try {
if (destFile.exists()) {
destFile.delete();
}
FileOutputStream out = new FileOutputStream(destFile);
try {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} finally {
out.flush();
try {
out.getFD().sync();
} catch (IOException e) {
}
out.close();
}
return true;
} catch (IOException e) {
return false;
}
}