尽管Java提供了java.io.File这样一个操作文件的类,但并没有提供一个复制文件的方法。
然而,当我们需要对磁盘上的文件进行处理的时候,这是一个很重要的方法。在这个时候我们往往不得不自己实现这样一个完成文件复制操作的方法。下面将会介绍4种常见的文件复制的实现,并比较下它们的性能。
使用FileStream
能找到的最常见经典例子。从文件A的输入流读取一批字节,写到文件B的输出流。
public static void copy(String from, String to, int bufferSize) {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(new File(from));
out = new FileOutputStream(new File(to));
byte[] buffer = new byte[bufferSize];
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
} catch (Exception e) {
Log.w(TAG + ":copy", "error occur while copy", e);
} finally {
safelyClose(TAG + ":copy", in);
safelyClose(TAG + ":copy", out);
}
}
复制代码
如你所见,这种实现方式需要多次读取数据,再写入将数据写入,因此受限于我们提供的buffer的大小,他的效率有点一般。
使用FileChannel
Java NIO类库里引入了一个叫transferFrom的方法,文档里说这是一个会比FileStream方式更快的复制操作。
public static void copyNio(String from, String to) {
FileChannel input = null;
FileChannel output = null;
try {
input = new FileInputStream(new File(from)).getChannel();
output = new FileOutputStream(new File(to)).getChannel();
output.transferFrom(input, 0, input.size());
} catch (Exception e) {
Log.w(TAG + "copyNio", "error occur while copy", e);
} finally {
safelyClose(TAG + "copyNio", input);
safelyClose(TAG + "copyNio", output);
}
}
复制代码
使用Apache Commons IO
Appache Commons IO 提供了一个FileUtils.copyFile(File from, File to)方法用于文件复制,如果项目里使用到了这个类库,使用这个方法是个不错的选择。它的内部也是使用Java NIO的FileChannel实现的。
private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
FileUtils.copyFile(source, dest);
}
复制代码
使用Java 7 的Files类
如果对Java 7 的使用有经验的话,那应该接触过Files这个工具类。
private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
FileUtils.copyFile(source, dest);
}
复制代码
性能
由于项目里没用到Apache Common IO,Android也不支持Java 7,因此我只测试了前两种,数据如下:
复制文件,大小2M
buffer大小
耗时
512
455
1024
238
2048
131
4096
82
8192
46
16384
36
32768
30
65536
29
131072
26
NIO方式
31
复制文件,大小4.5M
buffer大小
耗时
512
937
1024
523
2048
315
4096
155
8192
104
16384
108
32768
83
65536
74
131072
79
NIO方式
75
复制文件,大小8M
buffer大小
耗时
512
1774
1024
942
2048
488
4096
311
8192
225
16384
169
32768
154
65536
129
131072
121
NIO方式
108
复制文件,大小161M
buffer大小
耗时
512
38561
1024
19994
2048
10747
4096
5500
8192
3857
16384
3327
32768
3201
65536
3288
131072
3281
NIO方式
3266
结论
从数据上可以看出,使用FileStream的方式,复制的效率跟我们的buffer大小取值关系很大,这无疑加大了我们使用它进行文件复制的负担。
而NIO的方式则不然,无论是小文件、还是大文件,它的效率都跟我们测试FileStream的最好水平相当!
因此,把FileStream这种老旧的实现方式从项目里挪走吧,是时候用上FileChannel了。
Written with StackEdit.