news 2026/6/10 15:53:04

如何使用 Java IO 进行文件复制?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何使用 Java IO 进行文件复制?

Java IO 文件复制完全指南:从基础到高效(附完整代码实操)

文件复制是 Java IO 最核心的实战场景之一,无论是文本文件、图片、视频还是压缩包,都可以通过 IO 流实现复制。核心原则是:用字节流处理所有文件类型(万能方案),用缓冲流提升效率,用 NIO 简化代码。本文将分 4 种主流实现方式,从基础到进阶,带你彻底掌握文件复制。

一、核心前提(避免踩坑)

  1. 必须用字节流:字符流仅适用于文本文件,复制图片、视频等二进制文件会导致文件损坏,因此所有复制方案均基于字节流;
  2. 缓冲区是效率关键:直接读写单个字节效率极低,用字节数组(缓冲区)批量读写可大幅提升性能;
  3. 资源必须关闭:IO 流是稀缺资源,需用try-with-resources自动关闭(Java 7+ 推荐),避免资源泄露;
  4. 路径处理:需区分相对路径和绝对路径,避免“文件找不到”错误(如test.jpg是项目根目录,src/main/resources/test.jpg是资源目录)。

二、4 种文件复制实现方案(从基础到高效)

方案 1:基础字节流(FileInputStream + FileOutputStream)

最原始的实现方式,直接操作基础字节流,适合理解复制原理(新手入门必学)。

实现代码
importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;/** * 基础字节流文件复制(无缓冲,适合小文件) */publicclassBasicFileCopy{publicstaticvoidmain(String[]args){// 源文件路径(必须存在)、目标文件路径(不存在会自动创建)StringsourcePath="source.jpg";// 可替换为绝对路径:C:/source.jpgStringtargetPath="target_basic.jpg";longstartTime=System.currentTimeMillis();// 计时开始// try-with-resources 自动关闭流,无需手动 close()try(FileInputStreamfis=newFileInputStream(sourcePath);FileOutputStreamfos=newFileOutputStream(targetPath)){intsingleByte;// 存储每次读取的单个字节(0-255)// 循环读取:read() 返回 -1 表示读取完毕while((singleByte=fis.read())!=-1){fos.write(singleByte);// 逐个字节写入}fos.flush();// 强制刷新缓冲区,确保数据写入longcostTime=System.currentTimeMillis()-startTime;System.out.println("基础字节流复制完成!耗时:"+costTime+"ms");}catch(IOExceptione){System.err.println("复制失败:"+e.getMessage());e.printStackTrace();}}}
代码说明
  • 核心逻辑:fis.read()逐个读取字节,fos.write()逐个写入,本质是“字节级拷贝”;
  • 优点:代码简单,易理解,无需额外包装;
  • 缺点:效率极低(频繁磁盘 IO),仅适合100KB 以下的小文件,大文件(如 100MB 视频)会卡顿。

方案 2:基础字节流 + 缓冲区(推荐入门使用)

在方案 1 基础上添加字节数组缓冲区,批量读写字节,效率比方案 1 提升 10-100 倍,是日常开发的“基础优选方案”。

实现代码
importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;/** * 基础字节流 + 缓冲区(适合中、小文件,效率较高) */publicclassBufferedArrayFileCopy{publicstaticvoidmain(String[]args){StringsourcePath="source.mp4";// 测试大文件(如 100MB 视频)StringtargetPath="target_buffered_array.mp4";longstartTime=System.currentTimeMillis();try(FileInputStreamfis=newFileInputStream(sourcePath);FileOutputStreamfos=newFileOutputStream(targetPath)){// 缓冲区:4KB(常用最优大小,可调整为 8192、16384 等 2^n 数值)byte[]buffer=newbyte[4096];intreadLen;// 记录每次实际读取的字节数(最多为缓冲区大小)// 批量读取:read(buffer) 填充缓冲区,返回实际读取长度while((readLen=fis.read(buffer))!=-1){// 写入实际读取的字节(避免写入缓冲区中未使用的部分)fos.write(buffer,0,readLen);}fos.flush();longcostTime=System.currentTimeMillis()-startTime;System.out.println("缓冲区字节流复制完成!耗时:"+costTime+"ms");}catch(IOExceptione){System.err.println("复制失败:"+e.getMessage());e.printStackTrace();}}}
代码说明
  • 核心优化:byte[] buffer = new byte[4096]一次性读取 4KB 数据,减少磁盘 IO 次数(IO 是磁盘操作,耗时远高于内存操作);
  • readLen关键作用:最后一次读取可能未满缓冲区,write(buffer, 0, readLen)仅写入实际读取的字节,避免文件末尾出现垃圾数据;
  • 优点:效率高,代码简洁,无额外依赖,适合10MB-1GB 的中大型文件
  • 注意:缓冲区大小并非越大越好(如 1GB 缓冲区会占用过多内存),4KB/8KB/16KB 是平衡内存和效率的最优选择。

方案 3:缓冲流包装(BufferedInputStream + BufferedOutputStream)

Java 提供的专用缓冲流,内部自带缓冲区(默认 8KB),无需手动定义字节数组,是“高效简洁方案”。

实现代码
importjava.io.BufferedInputStream;importjava.io.BufferedOutputStream;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;/** * 缓冲流包装(推荐生产环境使用,高效且简洁) */publicclassBufferedStreamFileCopy{publicstaticvoidmain(String[]args){StringsourcePath="source.zip";// 压缩包等二进制文件StringtargetPath="target_buffered_stream.zip";longstartTime=System.currentTimeMillis();// 缓冲流包装基础字节流:BufferedInputStream 自带 8KB 缓冲区try(BufferedInputStreambis=newBufferedInputStream(newFileInputStream(sourcePath));BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream(targetPath))){byte[]buffer=newbyte[4096];// 可手动指定缓冲区大小(建议与内部缓冲区匹配)intreadLen;while((readLen=bis.read(buffer))!=-1){bos.write(buffer,0,readLen);}bos.flush();// 缓冲流需手动刷新,确保数据写入longcostTime=System.currentTimeMillis()-startTime;System.out.println("缓冲流复制完成!耗时:"+costTime+"ms");}catch(IOExceptione){System.err.println("复制失败:"+e.getMessage());e.printStackTrace();}}}
代码说明
  • 设计思想:装饰器模式(缓冲流包装基础流,增强缓冲功能);
  • 优势:
    1. 内部优化:BufferedInputStream会预读取数据到缓冲区,减少磁盘 IO;
    2. 代码简洁:无需关心缓冲区底层实现,仅需调用基础读写方法;
    3. 效率最优:比方案 2 略快(内部有额外优化),是生产环境首选方案
  • 注意:缓冲流必须调用flush()或等待缓冲区满,数据才会写入目标文件,try-with-resources关闭流时会自动刷新,但建议手动调用更稳妥。

方案 4:Java 8+ NIO.2(Files 工具类)

Java 7 引入的 NIO.2 提供了Files工具类,一行代码即可实现文件复制,底层优化充分,适合简洁场景。

实现代码
importjava.nio.file.Files;importjava.nio.file.Paths;importjava.nio.file.StandardCopyOption;importjava.io.IOException;/** * NIO.2 Files 工具类(Java 8+ 推荐,一行代码复制) */publicclassNioFilesCopy{publicstaticvoidmain(String[]args){StringsourcePath="source.pdf";StringtargetPath="target_nio.pdf";longstartTime=System.currentTimeMillis();try{// 核心方法:Files.copy(源路径, 目标路径, 复制选项)Files.copy(Paths.get(sourcePath),// 源文件路径(Path 对象)Paths.get(targetPath),// 目标文件路径StandardCopyOption.REPLACE_EXISTING// 选项:目标文件存在则覆盖);longcostTime=System.currentTimeMillis()-startTime;System.out.println("NIO Files 复制完成!耗时:"+costTime+"ms");}catch(IOExceptione){System.err.println("复制失败:"+e.getMessage());e.printStackTrace();}}}
代码说明
  • 核心优点:
    1. 代码极简:一行代码完成复制,无需手动处理流;
    2. 底层高效:内部使用 NIO 通道(Channel)和缓冲区,性能不逊于缓冲流;
    3. 功能强大:支持多种复制选项(如覆盖、原子操作等);
  • 常用复制选项:
    • StandardCopyOption.REPLACE_EXISTING:目标文件存在则覆盖(默认不覆盖,会抛异常);
    • StandardCopyOption.COPY_ATTRIBUTES:复制文件属性(如创建时间、权限);
    • StandardCopyOption.ATOMIC_MOVE:原子操作(仅适用于同一文件系统);
  • 适用场景:快速实现复制,无需自定义缓冲区或流,适合日常开发、脚本工具等场景。

三、常见问题与避坑指南

1. 文件找不到异常(FileNotFoundException)

  • 原因:源文件路径错误,或源文件不存在;
  • 解决方案:
    • 用绝对路径测试(如C:/Users/xxx/source.jpg);
    • 读取资源目录文件(如src/main/resources)时,用类加载器获取路径:
      // 获取 resources 下的文件路径StringsourcePath=NioFilesCopy.class.getClassLoader().getResource("source.jpg").getPath();

2. 目标文件被占用(IOException: 另一个程序正在使用此文件)

  • 原因:目标文件已被其他程序打开(如图片被图片查看器占用);
  • 解决方案:关闭占用目标文件的程序,或更换目标文件名称。

3. 复制大文件内存溢出(OutOfMemoryError)

  • 原因:方案 1 中逐个字节读取效率低,或缓冲区设置过大(如 1GB);
  • 解决方案:使用方案 2/3/4,缓冲区设置为 4KB-16KB,避免一次性加载大量数据到内存。

4. 复制后文件损坏

  • 原因:误用字符流复制二进制文件(如FileReader/FileWriter);
  • 解决方案:所有文件复制均使用字节流(InputStream/OutputStream)或 NIOFiles工具类。

四、4 种方案对比与选择建议

方案核心类优点缺点适用场景
基础字节流FileInputStream + FileOutputStream代码简单,易理解效率极低新手学习,小文件(<100KB)
基础字节流+缓冲区FileInputStream + FileOutputStream + 字节数组效率高,无额外依赖需手动管理缓冲区中大型文件(10MB-1GB),需自定义缓冲区
缓冲流包装BufferedInputStream + BufferedOutputStream效率最优,代码简洁需手动刷新生产环境首选,各类文件(推荐)
NIO.2 FilesFiles.copy()一行代码,底层优化灵活性低(难自定义)日常开发、脚本工具,无需自定义逻辑

最终选择建议:

  • 学习阶段:先掌握方案 1(理解原理)→ 方案 2(掌握缓冲区);
  • 开发阶段:优先使用方案 3(缓冲流)或方案 4(NIO Files),兼顾效率和简洁性;
  • 大文件(>1GB):方案 3(缓冲流)或方案 4(NIO),避免内存溢出。

总结

Java 文件复制的核心是“字节流 + 缓冲区”,无论哪种方案,本质都是“读取源文件字节 → 写入目标文件字节”。新手建议从基础方案入手,理解流的读写逻辑和缓冲区原理;实际开发中优先使用缓冲流或 NIO Files 工具类,兼顾效率和代码简洁性。记住:复制时始终用字节流,关闭资源用try-with-resources,缓冲区设置为 4KB-16KB,即可避免绝大多数问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 23:45:53

JavaScript高级:深入对象与内置构造函数

JavaScript 高级 - 第2天 了解面向对象编程的基础概念及构造函数的作用&#xff0c;体会 JavaScript 一切皆对象的语言特征&#xff0c;掌握常见的对象属性和方法的使用。 了解面向对象编程中的一般概念能够基于构造函数创建对象理解 JavaScript 中一切皆对象的语言特征理解引用…

作者头像 李华
网站建设 2026/6/10 14:05:10

月访问量破 2500 万,yeeyi亿忆成为澳洲华人生活信息核心平台

yeeyi亿忆 以其 月访问量 2500 万、注册用户 300 万、月活跃 40 万 的规模,在澳洲华人平台中保持极高的使用率。凭借 20 年持续运营经验,它已成为华人在澳洲生活、求职、找房与经营生意的重要信息中心。平台租房板块是其高流量来源之一,覆盖澳洲五大主要城市的真实房源。无论是…

作者头像 李华
网站建设 2026/6/10 14:03:37

React Native SVG开发实战:从图标到动画的完整解决方案

React Native SVG开发实战&#xff1a;从图标到动画的完整解决方案 【免费下载链接】react-native-svg 项目地址: https://gitcode.com/gh_mirrors/reac/react-native-art-svg "为什么我的应用图标在高分辨率屏幕上会模糊&#xff1f;" "为什么同样的动…

作者头像 李华
网站建设 2026/6/9 18:59:59

MongoDB实时数据同步终极指南:mongo-connector快速上手教程

MongoDB实时数据同步终极指南&#xff1a;mongo-connector快速上手教程 【免费下载链接】mongo-connector MongoDB data stream pipeline tools by YouGov (adopted from MongoDB) 项目地址: https://gitcode.com/gh_mirrors/mo/mongo-connector 你是否曾为MongoDB数据的…

作者头像 李华
网站建设 2026/6/10 14:00:43

5分钟掌握Dify.AI SQL生成:告别复杂查询语法的终极指南

5分钟掌握Dify.AI SQL生成&#xff1a;告别复杂查询语法的终极指南 【免费下载链接】dify 一个开源助手API和GPT的替代品。Dify.AI 是一个大型语言模型&#xff08;LLM&#xff09;应用开发平台。它整合了后端即服务&#xff08;Backend as a Service&#xff09;和LLMOps的概念…

作者头像 李华
网站建设 2026/6/10 6:45:33

Pyperclip:让Python剪贴板操作变得简单高效的跨平台利器

Pyperclip&#xff1a;让Python剪贴板操作变得简单高效的跨平台利器 【免费下载链接】pyperclip Python module for cross-platform clipboard functions. 项目地址: https://gitcode.com/gh_mirrors/py/pyperclip 在现代编程工作中&#xff0c;剪贴板操作是极其常见的需…

作者头像 李华