最近项目里有个需求需要实现文件拷贝,在java中文件拷贝流的读写,很容易就想到IO中的InputStream和OutputStream之类的,但是上网查了一下文件拷贝也是有很多种方法的,除了IO,还有NIO、Apache提供的工具类、JDK自带的文件拷贝方法

IO拷贝

public class IOFileCopy {    private static final int BUFFER_SIZE = 1024;    public static void copyFile(String source, String target) {        long start = System.currentTimeMillis();        try(InputStream in = new FileInputStream(new File(source));            OutputStream out = new FileOutputStream(new File(target))) {            byte[] buffer = new byte[BUFFER_SIZE];            int len;            while ((len = in.read(buffer)) > 0) {                out.write(buffer, 0, len);            }            System.out.println(String.format("IO file copy cost %d msc", System.currentTimeMillis() - start));        } catch (Exception e) {            e.printStackTrace();        }    }}

传统IO中文件读取过程可以分为以下几步:

  • 内核从磁盘读取数据到缓冲区,这个过程由磁盘操作器通过DMA操作将数据从磁盘读取到内核缓冲区,该过程不依赖CPU
  • 用户进程在将数据从内核缓冲区拷贝到用户空间缓冲区
  • 用户进程从用户空间缓冲区读取数据

NIO拷贝

NIO进行文件拷贝有两种实现方式,一是通过管道,而是通过文件内存内存映射

public class NIOFileCopy {    public static void copyFile(String source, String target) {        long start = System.currentTimeMillis();        try(FileChannel input = new FileInputStream(new File(source)).getChannel();            FileChannel output = new FileOutputStream(new File(target)).getChannel()) {            output.transferFrom(input, 0, input.size());        } catch (Exception e) {            e.printStackTrace();        }        System.out.println(String.format("NIO file copy cost %d msc", System.currentTimeMillis() - start));    }}

文件内存映射:

把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,DMA 硬件可以填充对内核与用户空间进程同时可见的缓冲区了。用户进程直接从内存中读取文件内容,应用只需要和内存打交道,不需要进行缓冲区来回拷贝,大大提高了IO拷贝的效率。加载内存映射文件所使用的内存在Java堆区之外

public class NIOFileCopy2 {    public static void copyFile(String source, String target) {        long start = System.currentTimeMillis();        try(FileInputStream fis = new FileInputStream(new File(source));            FileOutputStream fos = new FileOutputStream(new File(target))) {            FileChannel sourceChannel = fis.getChannel();            FileChannel targetChannel = fos.getChannel();            MappedByteBuffer mappedByteBuffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, 0, sourceChannel.size());            targetChannel.write(mappedByteBuffer);        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        System.out.println(String.format("NIO memory reflect file copy cost %d msc", System.currentTimeMillis() - start));        File targetFile = new File(target);        targetFile.delete();    }}

NIO内存映射文件拷贝可以分为以下几步

NIO的内存映射实际上就是少了一次从内核空间拷贝到用户空间的过程,将对用户缓冲区的读改为从内存读取

Files#copyFile方法

public class FilesCopy {    public static void copyFile(String source, String target) {        long start = System.currentTimeMillis();        try {            File sourceFile = new File(source);            File targetFile = new File(target);            Files.copy(sourceFile.toPath(), targetFile.toPath());        } catch (IOException e) {            e.printStackTrace();        }        System.out.println(String.format("FileCopy file copy cost %d msc", System.currentTimeMillis() - start));    }}

FileUtils#copyFile方法

使用FileUtils之前需先引入依赖

  • 依赖 commons-io commons-io 2.4
  • FileUtils#copyFile封装类:FileUtilsCopy.javapublic class FileUtilsCopy { public static void copyFile(String source, String target) { long start = System.currentTimeMillis(); try { FileUtils.copyFile(new File(source), new File(target)); } catch (IOException e) { e.printStackTrace(); } System.out.println(String.format("FileUtils file copy cost %d msc", System.currentTimeMillis() - start)); } }

性能比较

既然有这么多种实现方法,肯定要从中选择性能最佳的

测试环境:

  • windows 10
  • CPU 6核
  • JDK1.8

测试代码:PerformTest.java

public class PerformTest {    private static final String source1 = "input/test1.txt";    private static final String source2 = "input/test2.txt";    private static final String source3 = "input/test3.txt";    private static final String source4 = "input/test4.txt";    private static final String target1 = "output/test1.txt";    private static final String target2 = "output/test2.txt";    private static final String target3 = "output/test3.txt";    private static final String target4 = "output/test4.txt";    public static void main(String[] args) {        IOFileCopy.copyFile(source1, target1);        NIOFileCopy.copyFile(source2, target2);        FilesCopy.copyFile(source3, target3);        FileUtilsCopy.copyFile(source4, target4);    }}

总共执行了五次,读写的文件大小分别为9KB、23KB、239KB、1.77MB、12.7MB

注意:单位均为毫秒

从执行结果来看:

  • 文件很小时 => IO > NIO【内存映射】> NIO【管道】 > Files#copy > FileUtils#copyFile
  • 在文件较小时 => NIO【内存映射】> IO > NIO【管道】 > Files#copy > FileUtils#copyFile
  • 在文件较大时 => NIO【内存映射】> > NIO【管道】> IO > Files#copy > FileUtils#copyFile
  • 修改IO缓冲区大小对拷贝效率有影响,但是并不是越大性能越好,稍大于拷贝文件大小即可

文件较小时,IO效率高于NIO,NIO底层实现较为复杂,NIO的优势不明显。同时NIO内存映射初始化耗时,所以在文件较小时和IO复制相比没有优势

如果追求效率可以选择NIO的内存映射去实现文件拷贝,但是对于大文件使用内存映射拷贝要格外关注系统内存的使用率。推荐:大文件拷贝使用内存映射,原文是这样的:

For most operating systems, mapping a file into memory is moreexpensive than reading or writing a few tens of kilobytes of data viathe usual {@link #read read} and {@link #write write} methods.  From thestandpoint of performance it is generally only worth mapping relativelylarge files into memory

绝大多数操作系统的内存映射开销大于IO开销

同时通过测试结果来看,工具类和JDK提供的文件复制方法效果并不高,如果不追求效率还是可以使用一下,毕竟能少写一行代码就少写一行代码,写代码没有摸鱼来的快乐

来源:https://juejin.im/post/5e2523686fb9a030051f013e

system文件_大文件拷贝,试试NIO的内存映射相关推荐

  1. nio java 内核拷贝_大文件拷贝,试试NIO的内存映射

    最近项目里有个需求需要实现文件拷贝,在java中文件拷贝流的读写,很容易就想到IO中的InputStream和OutputStream之类的,但是上网查了一下文件拷贝也是有很多种方法的,除了IO,还有 ...

  2. formdata上传文件_大文件分片断点上传实现思路以及方案

    作者:yeyan1996| 来源:掘金https://juejin.im/post/5dff8a26e51d4558105420ed 前言 我在面试的时候确实被问到了这个问题,而且是一道在线 codi ...

  3. mac u盘文件过大 拷贝不进去_使用mac时文件太大无法拷贝怎么办

    高新科技的不断发展,我们对文件储存需求越来越大,无论是手机还是电脑文件的存储经常会非常大,那么对于这些大文件的拷贝,我们常常会遇到文件太大无法拷贝的问题,下面小编就针对mac用户来教大家如何解决这一问 ...

  4. mac u盘文件过大 拷贝不进去_Mac文件太大无法拷贝怎么办?Mac文件太大无法复制到u盘解决办法...

    现在的网速是越来越快了,各种在线传输文件还是算比较快了,若遇到像7.8个GB的文件,还是U盘来得实在,但是很的多Mac用户在向U盘拷贝文件时总会遇到"文件太大,无法拷贝"的错误提示 ...

  5. Mac文件太大无法拷贝怎么办?Mac文件太大无法复制到u盘解决办法

    当你执行完以下操作之后,你的u 盘会被清空, 如果在格式之前有资料,请提前备份!!!! 现在的网速是越来越快了,各种在线传输文件还是算比较快了,若遇到像7.8个GB的文件,还是U盘来得实在,但是很的多 ...

  6. mac u盘文件过大 拷贝不进去_mac文件太大无法复制到u盘怎么办-mac文件太大无法拷贝解决方法 - 河东软件园...

    在日常的学习/生活/工作中我们常常使用U盘储存文件,而想必许多用户在Mac上将比较大的文件拷贝到U盘时,常常会出现"文件太大无法拷贝"的错误提示,而此时我们会发现,其实我们的U盘明 ...

  7. python按行读取文件效率高吗_Python按行读取文件的实现方法【小文件和大文件读取】...

    本文实例讲述了Python按行读取文件的实现方法.分享给大家供大家参考,具体如下: 小文件: #coding=utf-8 #author: walker #date: 2013-12-30 #func ...

  8. VC++中使用内存映射文件处理大文件

    引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...

  9. Python 生成大量文件及大文件

    Python 生成大量文件及大文件 很多时候测试需要大量的文件和很大的文件,这些手动操作是非常麻烦的,现在来看看使用python自动生成 一次生成大量小文件(速度很慢) import os impor ...

最新文章

  1. InitializeComponent System.StackOverflowException
  2. awk分析nginx日志里面的接口响应时间
  3. 我的Dll(动态链接库)学习笔记(转)
  4. Tomcat不能自动编译JSP文件问题的一种解决方法
  5. IO流(八)之InputStreamReader类与OutputStreamWriter类
  6. 《TensorFlow技术解析与实战》学习笔记1
  7. OSPF在企业网络中的应用
  8. 【毕业设计】基于Android的家校互动平台开发(内含完整代码和所有文档)——爱吖校推(你关注的,我们才推)...
  9. win10下SVN图标不显示
  10. win11系统完全使用ie浏览器的方法
  11. winSCP start
  12. zk集群和clickhouse集群搭建
  13. linux 域名劫持,域名被劫持处理方案
  14. 《数据结构课程设计》实验预习
  15. Excel 划分各分数段并统计各分数段的人数
  16. 高级渗透之VBS调用WMI接口
  17. 驱动精灵 v9.61 去广告最终版绿色清爽单文件
  18. 23_字符串的格式化_format 函数_% 占位符 _ f-string _Template _模板字符等
  19. 开源3D激光SLAM项目BLAM
  20. 为泰泽铺路, Intel宣布32nm Atom正式出货 规格详解

热门文章

  1. python网络编程—UDP的echo服务
  2. 密码学-hash散列表
  3. (12)调用门阶段测试
  4. 操作系统是如何使用重定位表的
  5. 【安全工具】浅谈编写Java代码审计工具
  6. CString类的用法总结
  7. MySQL修改和删除触发器(DROP TRIGGER)
  8. 5、CSS 派生选择器
  9. “高级”数据结构——树状数组
  10. HDU1862 EXCEL排序