system文件_大文件拷贝,试试NIO的内存映射
最近项目里有个需求需要实现文件拷贝,在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的内存映射相关推荐
- nio java 内核拷贝_大文件拷贝,试试NIO的内存映射
最近项目里有个需求需要实现文件拷贝,在java中文件拷贝流的读写,很容易就想到IO中的InputStream和OutputStream之类的,但是上网查了一下文件拷贝也是有很多种方法的,除了IO,还有 ...
- formdata上传文件_大文件分片断点上传实现思路以及方案
作者:yeyan1996| 来源:掘金https://juejin.im/post/5dff8a26e51d4558105420ed 前言 我在面试的时候确实被问到了这个问题,而且是一道在线 codi ...
- mac u盘文件过大 拷贝不进去_使用mac时文件太大无法拷贝怎么办
高新科技的不断发展,我们对文件储存需求越来越大,无论是手机还是电脑文件的存储经常会非常大,那么对于这些大文件的拷贝,我们常常会遇到文件太大无法拷贝的问题,下面小编就针对mac用户来教大家如何解决这一问 ...
- mac u盘文件过大 拷贝不进去_Mac文件太大无法拷贝怎么办?Mac文件太大无法复制到u盘解决办法...
现在的网速是越来越快了,各种在线传输文件还是算比较快了,若遇到像7.8个GB的文件,还是U盘来得实在,但是很的多Mac用户在向U盘拷贝文件时总会遇到"文件太大,无法拷贝"的错误提示 ...
- Mac文件太大无法拷贝怎么办?Mac文件太大无法复制到u盘解决办法
当你执行完以下操作之后,你的u 盘会被清空, 如果在格式之前有资料,请提前备份!!!! 现在的网速是越来越快了,各种在线传输文件还是算比较快了,若遇到像7.8个GB的文件,还是U盘来得实在,但是很的多 ...
- mac u盘文件过大 拷贝不进去_mac文件太大无法复制到u盘怎么办-mac文件太大无法拷贝解决方法 - 河东软件园...
在日常的学习/生活/工作中我们常常使用U盘储存文件,而想必许多用户在Mac上将比较大的文件拷贝到U盘时,常常会出现"文件太大无法拷贝"的错误提示,而此时我们会发现,其实我们的U盘明 ...
- python按行读取文件效率高吗_Python按行读取文件的实现方法【小文件和大文件读取】...
本文实例讲述了Python按行读取文件的实现方法.分享给大家供大家参考,具体如下: 小文件: #coding=utf-8 #author: walker #date: 2013-12-30 #func ...
- VC++中使用内存映射文件处理大文件
引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...
- Python 生成大量文件及大文件
Python 生成大量文件及大文件 很多时候测试需要大量的文件和很大的文件,这些手动操作是非常麻烦的,现在来看看使用python自动生成 一次生成大量小文件(速度很慢) import os impor ...
最新文章
- InitializeComponent System.StackOverflowException
- awk分析nginx日志里面的接口响应时间
- 我的Dll(动态链接库)学习笔记(转)
- Tomcat不能自动编译JSP文件问题的一种解决方法
- IO流(八)之InputStreamReader类与OutputStreamWriter类
- 《TensorFlow技术解析与实战》学习笔记1
- OSPF在企业网络中的应用
- 【毕业设计】基于Android的家校互动平台开发(内含完整代码和所有文档)——爱吖校推(你关注的,我们才推)...
- win10下SVN图标不显示
- win11系统完全使用ie浏览器的方法
- winSCP start
- zk集群和clickhouse集群搭建
- linux 域名劫持,域名被劫持处理方案
- 《数据结构课程设计》实验预习
- Excel 划分各分数段并统计各分数段的人数
- 高级渗透之VBS调用WMI接口
- 驱动精灵 v9.61 去广告最终版绿色清爽单文件
- 23_字符串的格式化_format 函数_% 占位符 _ f-string _Template _模板字符等
- 开源3D激光SLAM项目BLAM
- 为泰泽铺路, Intel宣布32nm Atom正式出货 规格详解