尽管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.