`

【Java核心-基础】文件读写的底层数据传输方式 (用户空间 vs 内核空间)

    博客分类:
  • Java
 
阅读更多

按底层实现方式划分,Java文件读写有两种:用户空间拷贝 和 内核空间拷贝。

用户空间拷贝


 

数据传递需要在 用户空间 和 内核空间 之间转换

 

java.nio.Files.copy() 几个重载方法内部都是这种方式。 

典型用户空间数据拷贝:

void copy(InputStream source, OutputStream target) {
  byte[] buffer = new byte[8192];
  int n;
  while ((n = source.read(buffer)) > 0) {
    target.write(buffer, 0, n);
  }
}

 

内核空间拷贝


 

数据传递无需经过用户空间转换,直接在内核空间传递。(Linux 和 Unix 系统中所谓的“零拷贝”技术)
这种方式省去了 上下文切换 和 不必要的内存拷贝,性能可以更好。但是必须测试验证,有时候Stream操作反而更快。

 

java.nio.FileChannel.transferTo()transferFrom() 就是这种方式(《FileChannel 数据传输》)。
commons-io 中 org.apache.commons.io.FileUtils.copyFile() 中就有用到 transferFrom() :

// FILE_COPY_BUFFER_SIZE = 1024 * 1024 * 30 (30MB)

private static void doCopyFile(final File srcFile, final File destFile,
    final boolean preserveFileDate) {
  ...
  try (FileInputStream fis = new FileInputStream(srcFile);
    FileChannel input = fis.getChannel();
    FileOutputStream fos = new FileOutputStream(destFile);
    FileChannel output = fos.getChannel()) {
    final long size = input.size();
    long pos = 0;
    long count = 0;
    while (pos < size) {
      final long remain = size - pos;
      count = remain > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : remain;
      final long bytesCopied = output.transferFrom(input, pos, count);
      if (bytesCopied == 0) {
        break;
      }
      pos += bytesCopied;
    }
  }
  ...
}

 

注:JDK 11 中 java.io.InputStream 也有个 transferTo() 方法。但这个方法还是典型的用户空间数据拷贝。

 

  • 大小: 18.3 KB
  • 大小: 17 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics