赞
踩
下面看几个示例来比较一下各种文件操作的性能对比
将一个37M的文件test1.txt读出来然后写入到dest.txt,实现文件的拷贝。
示例代码:
@Test
public void perByteOperation() {
LOGGER.info("开始单字节单字节复制文件...");
long start = System.currentTimeMillis();
try (FileInputStream fis = new FileInputStream(TEST_PATH + "test1.txt");
FileOutputStream fos = new FileOutputStream(TEST_PATH + "dest.txt")) {
int i;
while ((i = fis.read()) != -1) {
fos.write(i);
}
} catch (Exception e) {
LOGGER.error("单字节单字节复制文件异常", e);
}
LOGGER.info("结束单字节单字节复制文件...,耗时:{}ms", System.currentTimeMillis() - start);
}
[INFO ][2020/09/08 08:55:03][main] - 开始单字节单字节复制文件...
[INFO ][2020/09/08 08:57:31][main] - 结束单字节单字节复制文件...,耗时:148090ms
耗时148s,可怕!
示例代码:
@Test public void bufferOperationWith100() { LOGGER.info("开始带100字节缓冲区复制文件..."); long start = System.currentTimeMillis(); try (FileInputStream fis = new FileInputStream(TEST_PATH + "test1.txt"); FileOutputStream fos = new FileOutputStream(TEST_PATH + "dest.txt")) { byte[] buf = new byte[100]; int len; while ((len = fis.read(buf)) != -1) { fos.write(buf, 0, len); } } catch (Exception e) { LOGGER.error("带100字节缓冲区复制文件", e); } LOGGER.info("开始带100字节缓冲区复制文件...,耗时:{}ms", System.currentTimeMillis() - start); }
[INFO ][2020/09/08 08:59:05][main] - 开始带100字节缓冲区复制文件...
[INFO ][2020/09/08 08:59:07][main] - 开始带100字节缓冲区复制文件...,耗时:2237ms
可见,增加了缓冲区之后,速度大大提高了。
BufferedStream采用了 private static int DEFAULT_BUFFER_SIZE = 8192; 8Kb的缓冲区。
示例代码:
@Test
public void bufferStreamByteOperation() {
LOGGER.info("开始带缓冲区复制文件...");
long start = System.currentTimeMillis();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(TEST_PATH + "test1.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_PATH + "dest.txt"))) {
int i;
while ((i = bis.read()) != -1) {
bos.write(i);
}
} catch (Exception e) {
LOGGER.error("带缓冲区复制文件文件异常", e);
}
LOGGER.info("开始带缓冲区复制文件...,耗时:{}ms", System.currentTimeMillis() - start);
}
[INFO ][2020/09/08 09:01:18][main] - 开始带缓冲区复制文件...
[INFO ][2020/09/08 09:01:20][main] - 开始带缓冲区复制文件...,耗时:2350ms
为啥我们使用了缓冲流,没有明显提高呢?原因是虽然读取写入使用了缓冲流,但bos.write(i);方法是按单字节写入的,调用次数过多。
@Test public void bufferStreamBufferOperation() { LOGGER.info("bufferStreamBufferOperation开始带缓冲区复制文件..."); long start = System.currentTimeMillis(); try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(TEST_PATH + "test1.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_PATH + "dest.txt"))) { byte[] buf = new byte[8196]; int i; while ((i = bis.read(buf)) != -1) { bos.write(buf, 0, i); } } catch (Exception e) { LOGGER.error("带缓冲区复制文件文件异常", e); } LOGGER.info("开始带缓冲区复制文件...,耗时:{}ms", System.currentTimeMillis() - start); }
[INFO ][2020/09/08 09:05:02][main] - bufferStreamBufferOperation开始带缓冲区复制文件...
[INFO ][2020/09/08 09:05:02][main] - 开始带缓冲区复制文件...,耗时:132ms
@Test public void streamBufferOperation() { LOGGER.info("streamBufferOperation开始带缓冲区复制文件..."); long start = System.currentTimeMillis(); try (FileInputStream fis = new FileInputStream(TEST_PATH + "test1.txt"); FileOutputStream fos = new FileOutputStream(TEST_PATH + "dest.txt")) { byte[] buf = new byte[8196]; int i; while ((i = fis.read(buf)) != -1) { fos.write(buf, 0, i); } } catch (Exception e) { LOGGER.error("带缓冲区复制文件文件异常", e); } LOGGER.info("开始带缓冲区复制文件...,耗时:{}ms", System.currentTimeMillis() - start); }
[INFO ][2020/09/08 09:06:27][main] - streamBufferOperation开始带缓冲区复制文件...
[INFO ][2020/09/08 09:06:27][main] - 开始带缓冲区复制文件...,耗时:120ms
我们可以看到4,5花费的时间差不多,但我们推荐第4种方案。但在实际代码中每次需要读
取的字节数很可能不是固定的,有的时候读取几个字节,有的时候读取几百字节,这个时候有一个固定大小较大的缓冲,也就是使用 BufferedInputStream 和
BufferedOutputStream 做为后备的稳定的二次缓冲,就非常有意义了。
DMA(直接内存访问),数据从磁盘经过总线直接发送到目标文件,无需经过内存和 CPU 进行数据中转,这种方式更快。
/** * @Description 采用的是DMA(直接内存访问)也就是数据从磁盘经过总线直接发送到目标 * 文件,无需经过内存和 CPU 进行数据中转: * @author chenwb * @date 2020/9/8 9:21 */ @Test public void fileChannelOperation() throws IOException { LOGGER.info("fileChannelOperation开始复制文件..."); long start = System.currentTimeMillis(); FileChannel in = FileChannel.open(Paths.get(TEST_PATH + "test1.txt"), StandardOpenOption.READ); FileChannel out = FileChannel.open(Paths.get(TEST_PATH + "dest.txt"), StandardOpenOption.CREATE, StandardOpenOption.WRITE); in.transferTo(0, in.size(), out); LOGGER.info("结束复制文件...,耗时:{}ms", System.currentTimeMillis() - start); }
[INFO ][2020/09/08 09:22:30][main] - fileChannelOperation开始复制文件...
[INFO ][2020/09/08 09:22:30][main] - 结束复制文件...,耗时:48ms
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。