Java 核心技术面试精讲
杨晓峰
前 Oracle 首席工程师
125942 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 44 讲
Java 核心技术面试精讲
15
15
1.0x
00:00/00:00
登录|注册

第12讲 | Java有几种文件拷贝方式?哪一种最高效?

Files.copy方法
transferFrom方法
transferTo方法
FileOutputStream
FileInputStream
NIO机制用于channel读取过程中的分片写入
JVM内存结构
Native Memory Tracking
垃圾收集和回收建议
内存和JVM参数影响
MappedByteBuffer
堆内和堆外Buffer
mark
limit
position
capacity
零拷贝技术
上下文切换
用户态空间和内核态空间
NIO transferTo/From方式可能更快
与操作系统和配置相关
Java标准类库
java.nio类库
java.io类库
一课一练
跟踪和诊断Direct Buffer内存占用
Direct Buffer
Buffer分类与使用
机制区别
拷贝效率
Java文件拷贝方式

该思维导图由 AI 生成,仅供参考

我在专栏上一讲提到,NIO 不止是多路复用,NIO 2 也不只是异步 IO,今天我们来看看 Java IO 体系中,其他不可忽略的部分。
今天我要问你的问题是,Java 有几种文件拷贝方式?哪一种最高效?

典型回答

Java 有多种比较典型的文件拷贝实现方式,比如:
利用 java.io 类库,直接为源文件构建一个 FileInputStream 读取,然后再为目标文件构建一个 FileOutputStream,完成写入工作。
public static void copyFileByStream(File source, File dest) throws
IOException {
try (InputStream is = new FileInputStream(source);
OutputStream os = new FileOutputStream(dest);){
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
}
}
或者,利用 java.nio 类库提供的 transferTo 或 transferFrom 方法实现。
public static void copyFileByChannel(File source, File dest) throws
IOException {
try (FileChannel sourceChannel = new FileInputStream(source)
.getChannel();
FileChannel targetChannel = new FileOutputStream(dest).getChannel
();){
for (long count = sourceChannel.size() ;count>0 ;) {
long transferred = sourceChannel.transferTo(
sourceChannel.position(), count, targetChannel); sourceChannel.position(sourceChannel.position() + transferred);
count -= transferred;
}
}
}
当然,Java 标准类库本身已经提供了几种 Files.copy 的实现。
对于 Copy 的效率,这个其实与操作系统和配置等情况相关,总体上来说,NIO transferTo/From 的方式可能更快,因为它更能利用现代操作系统底层机制,避免不必要拷贝和上下文切换。

考点分析

今天这个问题,从面试的角度来看,确实是一个面试考察的点,针对我上面的典型回答,面试官还可能会从实践角度,或者 IO 底层实现机制等方面进一步提问。这一讲的内容从面试题出发,主要还是为了让你进一步加深对 Java IO 类库设计和实现的了解。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了Java文件拷贝方式及其效率比较,重点介绍了利用java.io和java.nio类库进行文件拷贝的方式。在实际效率比较中,NIO的transferTo/From方式可能更快,因为它更能利用现代操作系统底层机制,避免不必要的拷贝和上下文切换。然而,实际的效率受操作系统和配置等因素影响,因此并不是绝对的。此外,文章还提到了面试角度的考察点和技术细节,强调了对底层机制和技术细节的了解和思考的重要性。另外,还介绍了拷贝实现机制分析、Java IO/NIO源码结构、掌握NIO Buffer、Direct Buffer和垃圾收集以及跟踪和诊断Direct Buffer内存占用等内容。总的来说,本文为读者提供了全面的技术知识和实践经验,对于Java文件拷贝方式的选择,读者需要综合考虑实际情况和需求,同时也需要对底层机制和技术细节有一定的了解和思考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 核心技术面试精讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(55)

  • 最新
  • 精选
  • 行者
    可以利用NIO分散-scatter机制来写入不同buffer。 Code: ByteBuffer header = ByteBuffer.allocate(128); ByteBuffer body = ByteBuffer.allocate(1024); ByteBuffer[] bufferArray = {header, body}; channel.read(bufferArray); 注意:该方法适用于请求头长度固定。

    作者回复: 赞

    2018-05-31
    3
    131
  • 13576788017
    杨老师,想问一下,一般要几年java经验才能达到看懂你文章的地步??我将近一年经验。。我发现我好几篇都看不懂。。底层完全不懂。。是我太菜了吗。。

    作者回复: 非常抱歉,具体哪几篇?公司对一年经验的工程师要求应该也不一样的

    2018-05-31
    20
    128
  • 乘风破浪
    零拷贝是不是可以理解为内核态空间与磁盘之间的数据传输,不需要再经过用户态空间?

    作者回复: 嗯

    2018-05-31
    53
  • 夏洛克的救赎
    请问老师您有参与jdk的开发吗

    作者回复: 是的,目前lead的团队主要是QE职责

    2018-05-31
    21
  • CC
    我Nio从没接触过,很难受,两年开发的

    作者回复: 不用担心,是理解有难度吗?

    2018-06-07
    17
  • vash_ace
    其实在初始化 DirectByteBuffer对象时,如果当前堆外内存的条件很苛刻时,会主动调用 System.gc()强制执行FGC。所以一般建议在使用netty时开启XX:+DisableExplicitGC

    作者回复: 对,检测不够时会尝试调system.gc,记得老版本有并发分配bug,会出oom;netty,文中提到了,它是hack到内部自己释放...

    2018-06-01
    3
    16
  • mongo
    杨老师,我也想请教,目前为止您的其他文章都理解的很好,到了上次专栏的NIO我理解的不是很好,今天的这篇可以说懵圈了。到了这一步想突破,应该往哪个方向?我自己感觉是因为基于这两个底层原理的上层应用使用的时候观察的不够深入,对原理反应的现象没有深刻感受,就是所谓还没有摸清楚人家长什么样。所以接下来我会认真在使用基于这些原理实现的上层应用过程中不断深挖和观察,比如认真学习dubbo框架(底层使用到了netty,netty的底层使用了NIO)来帮助我理解NIO。在这个过程中促进对dubbo的掌握,以此良性循环。不知道方向对不对?老师的学习方法是什么?请老师指点避坑。学习方法不对的话时间成本太可怕。

    作者回复: 我觉得思路不错,结合实践是非常好的;我自身也仅仅是理论上理解,并没有在大规模实践中踩坑,实践中遇到细节的“坑”其实是宝贝,所以你有更多优势;本文从基础角度出发,也是希望对其原理有个整体印象,至少被面试刨根问底时,可以有所准备,毕竟看问题的角度是不同的

    2018-05-31
    14
  • Len
    请教老师: 1. 经常看到 Java 进程的 RES 大小远超过设置的 Xmx,可以认为这就是 Direct Memory 的原因吗?如果是的话,可以简单的用堆实际占用的大小减去 RES 就是 Direct Memory 的大小吗? 2.可以认为 Direct Memory 不论在什么情况下都不会引起 Full GC,Direct Memory 的回收只是在 Full GC (或调用 System.gc())的时候顺带着回收下,是吗?

    作者回复: 1,一般不是,那东西有个默认大小的,metaspace codecache等等都会占用,后面有章节仔细分析 2,不是,它是利用sun.misc.Cleaner, 实际表现有瑕疵,经常要更依赖system gc去触发引用处理,9和8u有改进,我会有详解

    2018-05-31
    9
  • 老陈板
    本篇文章有恍然大悟的感觉,前面段时间有一家面试问了个这样的问题,我们发现服务器内存使用得特别高,但是堆内存也比较稳定,这种场景是你你会怎么排查?这里就涉及到堆外内存相关的问题!以前不知道有NMT这个工具,然后当时没答好,导致工资少了好多,早点读这篇文章多好。另外注意,sysyem.gc不一定会立即触发fgc,有个权值

    作者回复: 一个常见例子是,创建了一堆线程,实际占用内存(RSS)远比堆本身大

    2019-02-17
    8
  • 皮蛋
    杨老师,想问下如果想学操作系统的知识,阅读什么书比较适合,初学者

    作者回复: 可以看看《深入理解计算机系统》,如果有精力,再找本linux内核并配合实验,会很有用

    2018-11-02
    8
收起评论
显示
设置
留言
55
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部