Java IO与NIO来Copy文件的四种方法实现以及性能对比

使用Java的IO与NIO来Copy文件的四种方法实现以及性能对比

FileCopyRunner接口,定义了Copy文件的接口,等下在测试类中使用匿名内部类来实现。

package nio.channel;import java.io.File;public interface FileCopyRunner {void copyFile(File source , File target);
}

测试类:

  • benchmark():Copy文件ROUNDS(5次,并且返回耗费的平均时间(1.0F)*elapsed / ROUNDS
  • close():关闭资源。

完整代码(下面说四种方法):

package nio.channel;import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class FileCopyDemo {private static final int ROUNDS = 5;private static void benchmark(FileCopyRunner test ,File sourse , File target){long elapsed = 0L;for (int i = 0; i < ROUNDS; i++) {long startTime = System.currentTimeMillis();test.copyFile(sourse , target);elapsed += System.currentTimeMillis() - startTime;target.delete();}System.out.println(test+":"+(1.0F)*elapsed / ROUNDS);}public static void close(Closeable closeable){if(closeable != null){try {closeable.close();} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) {FileCopyRunner noBufferStreamCopy  = new FileCopyRunner() {@Overridepublic void copyFile(File sourse, File target) {InputStream fin = null;OutputStream fout = null;try {fin = new FileInputStream(sourse);fout = new FileOutputStream(target);int result;while((result = fin.read()) != -1){fout.write(result);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "noBufferStreamCopy";}};FileCopyRunner bufferedStreamCopy = new FileCopyRunner() {@Overridepublic void copyFile(File sourse, File target) {InputStream fin = null;OutputStream fout = null;try {fin = new BufferedInputStream(new FileInputStream(sourse));fout = new BufferedOutputStream(new FileOutputStream(target));byte[] buffer = new byte[8192];int result;while((result = fin.read(buffer)) != -1){fout.write(buffer , 0 ,result);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "bufferedStreamCopy";}};FileCopyRunner nioBufferCopy = new FileCopyRunner() {@Overridepublic void copyFile(File sourse, File target) {FileChannel fin = null;FileChannel fout = null;try {fin = new FileInputStream(sourse).getChannel();fout = new FileOutputStream(target).getChannel();ByteBuffer buffer = ByteBuffer.allocate(8192);while(fin.read(buffer) != -1){buffer.flip(); //开始读模式while(buffer.hasRemaining()){fout.write(buffer);}buffer.clear(); // 开始写模式}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "nioBufferCopy";}};FileCopyRunner nioTransferCopy = new FileCopyRunner() {@Overridepublic void copyFile(File sourse, File target) {FileChannel fin = null;FileChannel fout = null;try {fin = new FileInputStream(sourse).getChannel();fout = new FileOutputStream(target).getChannel();long transferred = 0;long size = fin.size();while(transferred != size){transferred += fin.transferTo(0,size,fout);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "nioTransferCopy";}};File one = new File("E:\\test\\1.png");File oneCopy = new File("E:\\test\\1-copy.png");System.out.println("---Copying one---");benchmark(noBufferStreamCopy , one , oneCopy);benchmark(bufferedStreamCopy , one , oneCopy);benchmark(nioBufferCopy , one , oneCopy);benchmark(nioTransferCopy , one , oneCopy);File two = new File("E:\\test\\2.mp4");File twoCopy = new File("E:\\test\\2-copy.mp4");System.out.println("---Copying two---");
//        benchmark(noBufferStreamCopy , two , twoCopy);benchmark(bufferedStreamCopy , two , twoCopy);benchmark(nioBufferCopy , two , twoCopy);benchmark(nioTransferCopy , two , twoCopy);File three = new File("E:\\test\\3.mp4");File threeCopy = new File("E:\\test\\3-copy.mp4");System.out.println("---Copying three---");
//        benchmark(noBufferStreamCopy , three , threeCopy);benchmark(bufferedStreamCopy , three , threeCopy);benchmark(nioBufferCopy , three , threeCopy);benchmark(nioTransferCopy , three , threeCopy);File four = new File("E:\\test\\4.avi");File fourCopy = new File("E:\\test\\4-copy.avi");System.out.println("---Copying four---");
//        benchmark(noBufferStreamCopy , four , fourCopy);benchmark(bufferedStreamCopy , four , fourCopy);benchmark(nioBufferCopy , four , fourCopy);benchmark(nioTransferCopy , four , fourCopy);}
}

匿名内部类一:

使用FileInputStreamFileOutputStream来Copy文件,它是一个字节一个字节进行read的,所以也是一个字节一个字节进行write的,read()的源码注释很清楚的写出来了,所以这种方法的性能特别差,等下用较大文件测试时,我们选择跳过这种方法(因为太久了),内部逻辑应该很简单吧,从read()的源码注释可以知道read()的返回值是介于0-255的值,其实就是读取的一个字节(8位)The value byte is returned as an int in the range 0 to 255。

     * Reads the next byte of data from the input stream. The value byte is* returned as an <code>int</code> in the range <code>0</code> to* <code>255</code>. If no byte is available because the end of the stream* has been reached, the value <code>-1</code> is returned. This method* blocks until input data is available, the end of the stream is detected,* or an exception is thrown.
        FileCopyRunner noBufferStreamCopy  = new FileCopyRunner() {@Overridepublic void copyFile(File source, File target) {InputStream fin = null;OutputStream fout = null;try {fin = new FileInputStream(source);fout = new FileOutputStream(target);int result;while((result = fin.read()) != -1){fout.write(result);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "noBufferStreamCopy";}};

匿名内部类二:

第二种方法使用BufferedInputStreamBufferedOutputStream来进行文件的Copy,它们会产生一个缓冲区,默认大小都是8192字节,源码如下:

    private static int DEFAULT_BUFFER_SIZE = 8192;/*** Creates a <code>BufferedInputStream</code>* and saves its  argument, the input stream* <code>in</code>, for later use. An internal* buffer array is created and  stored in <code>buf</code>.** @param   in   the underlying input stream.*/public BufferedInputStream(InputStream in) {this(in, DEFAULT_BUFFER_SIZE);}
    /*** Creates a new buffered output stream to write data to the* specified underlying output stream.** @param   out   the underlying output stream.*/public BufferedOutputStream(OutputStream out) {this(out, 8192);}

利用缓冲区,会大大提升性能,因为避免了频繁的打开、关闭文件,有了缓冲区,我们每次对文件进行读、写操作,都可以读、写更多字节数据,减少了打开、关闭文件等操作的次数。

        FileCopyRunner bufferedStreamCopy = new FileCopyRunner() {@Overridepublic void copyFile(File source, File target) {InputStream fin = null;OutputStream fout = null;try {fin = new BufferedInputStream(new FileInputStream(source));fout = new BufferedOutputStream(new FileOutputStream(target));byte[] buffer = new byte[8192];int result;while((result = fin.read(buffer)) != -1){fout.write(buffer , 0 ,result);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "bufferedStreamCopy";}};

 

匿名内部类三:

第三种方法使用NIO中的ChannelBuffer来进行Copy文件。

Java 网络编程-NIO原理概述

和上一种方法一样,这里创建8192字节Buffer,方便进行性能的对比。

ByteBuffer buffer = ByteBuffer.allocate(8192);

下面两种操作,大家应该知道吧,不知道就往下看。

buffer.flip(); //开始读模式
buffer.clear(); // 开始写模式

 源码如下(先不管mark有什么用):

    private int position = 0;private int limit;private int capacity;public final Buffer flip() {limit = position;position = 0;mark = -1;return this;}public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;}

 

下面这张图应该描述的很清楚。

写模式:position位置之前的数据都是写入的(包括position位置),每写入一字节数据,position++,所以clear()position置0,是不是就说明开始准备要写入了,并且limit = capacity,即进入写模式。
读模式:写入数据后,0位置到position位置的数据都是写入的,调用flip(),将limit置成position,而position置成0,所以position(0)到limit(原position位置)是不是就是要被读取的数据范围,即进入读模式


 

        FileCopyRunner nioBufferCopy = new FileCopyRunner() {@Overridepublic void copyFile(File source, File target) {FileChannel fin = null;FileChannel fout = null;try {fin = new FileInputStream(source).getChannel();fout = new FileOutputStream(target).getChannel();ByteBuffer buffer = ByteBuffer.allocate(8192);while(fin.read(buffer) != -1){buffer.flip(); //开始读模式while(buffer.hasRemaining()){fout.write(buffer);}buffer.clear(); // 开始写模式}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "nioBufferCopy";}};

匿名内部类四:

第四种方法只使用NIOChannel来进行文件的Copy,Channel通过transferTo()可以把数据写入另一个Channel
transferTo()的源码注释也可以看出。

Transfers bytes from this channel’s file to the given writable byte channel.

 

        FileCopyRunner nioTransferCopy = new FileCopyRunner() {@Overridepublic void copyFile(File source, File target) {FileChannel fin = null;FileChannel fout = null;try {fin = new FileInputStream(source).getChannel();fout = new FileOutputStream(target).getChannel();long transferred = 0;long size = fin.size();while(transferred != size){transferred += fin.transferTo(0,size,fout);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally{close(fin);close(fout);}}@Overridepublic String toString() {return "nioTransferCopy";}};

 

性能对比

文件详情如下:

  • 1.png(37KB)。
  • 2.mp4(3.92MB)。
  • 3.mp4(132MB)。
  • 4.avi(638MB)。

每种方法Copy文件5次,计算平均耗时(第一种方法除外,因为它太慢了)。

输出:

---Copying one---
noBufferStreamCopy:143.4
bufferedStreamCopy:0.4
nioBufferCopy:1.0
nioTransferCopy:0.4
---Copying two---
bufferedStreamCopy:5.0
nioBufferCopy:5.8
nioTransferCopy:2.6
---Copying three---
bufferedStreamCopy:161.0
nioBufferCopy:154.0
nioTransferCopy:90.8
---Copying four---
bufferedStreamCopy:1659.0
nioBufferCopy:1294.4
nioTransferCopy:1266.6

我测试了很多次,需要缓冲区的方法,性能跟文件大小、缓冲区大小都有关系。

不过,第四种方法性能还是挺不错的。

如果有说错的地方,请大家不吝赐教

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】明析部分C语言内存函数

目录 1.memcpy 2.memmove 3.memset 4.memcmp 以下都是内存函数&#xff0c;作用单位均是字节 1.memcpy memcpy是C/C语言中的一个内存拷贝函数&#xff0c;其原型为&#xff1a; void* memcpy(void* dest, const void* src, size_t n);目标空间&#xff08;字节&#xff09…

【Linux系统化学习】应用层——HTTPS协议

目录 什么是加密、解密 为什么要加密 臭名昭著的”运营商劫持“ 常见的加密方式 对称加密 非对称加密 数据摘要&&数据指纹 两个用途 HTTPS的工作过程探究 方案1——只是用对称加密 方案2——只使用非对称加密 方案3——双方都是用非对称加密 方案4——对称…

科技引领乡村振兴新潮流:运用现代信息技术手段,提升农业生产和乡村管理效率,打造智慧化、现代化的美丽乡村

一、引言 随着科技的不断进步&#xff0c;现代信息技术已经渗透到社会的各个领域&#xff0c;成为推动社会发展的重要力量。在乡村振兴战略的背景下&#xff0c;科技的力量同样不容忽视。本文旨在探讨如何运用现代信息技术手段&#xff0c;提升农业生产和乡村管理效率&#xf…

java自学阶段二:JavaWeb开发--day04(Maven学习)

day04学习笔记 一、学习目标 1.了解maven的基础概念&#xff1b; 2.学会maven的部署&#xff1b; 3.maven的作用&#xff1a;标准化&#xff1b;方便找依赖 maven就是一个开源项目&#xff0c;专门用来管理和构建Java项目的&#xff1b;我们自己写的项目结构可能会千奇百怪&am…

每日一题《leetcode--116.填充每个结点的下一个右侧结点》

https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/ 题目要求给每个结点的next指针进行填充&#xff0c;使每个结点的next指针指向其下一个右侧结点。如果右侧没有结点&#xff0c;则将next指针设置为空。 struct Node* connect(struct Node* root) {…

快速搭建 WordPress 外贸电商网站指南

本指南全面解析了在 Hostinger 平台上部署 WordPress 外贸电商网站的详细步骤&#xff0c;涵盖托管方案选择、WordPress 一键安装、主题挑选与演示数据导入、主题个性化定制、SEO插件插件 AIOSEO 安装、通过 GTranslate 实现多语言自动翻译、地区访问控制插件&#xff0c;助力用…

人工智能(Educoder)-- 机器学习 -- 神经网络(初级)

第一关 注&#xff1a; 神经网络的起源和应用 起源&#xff1a;神经网络最早由心理学家和神经学家开创&#xff0c;目的是模拟生物神经系统对真实世界物体的交互反应。应用&#xff1a;现代神经网络用于分类&#xff08;如图像识别、文本分类&#xff09;和数值预测&#xff08…

Windows下安装部署rocketmq

1.1.下载安装rocketmq 下载 | RocketMQ 下载完后解压到自定义目录&#xff0c;MQ解压路径\rocketmq-all-4.6.0-bin-release&#xff1b;&#xff08;Windows10系统解压路径不要出现空格&#xff09; 1.2.配置环境变量 配置环境变量&#xff0c;变量名&#xff1a;ROCKETM…

深入探索C/C++内存管理

目录 C/C内存分布 C语言中动态内存管理方式 calloc realloc free C中动态内存管理方式 new和delete操作内置类型 new和delete操作自定义类型 operator new和operator delete函数 new和delete的实现原理 内置类型 自定义类型 定位new和表达式(placement-new) 常见面试…

C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

机器学习之词袋模型

目录 1 词袋模型基本概念 2 词袋模型的表示方法 2.1 三大方法 1 独热表示法&#xff08;One-Hot&#xff09; 2 词频表示法&#xff08;Term Frequency, TF&#xff09; 3 词频-逆文档频率表示法&#xff08;TF-IDF&#xff09; 2.2 例子 1 词袋模型基本概念 词袋模型&a…

《Effective Objective-C 2.0》读书笔记——熟悉Objective-C

目录 第一章&#xff1a;熟悉Objective-C第1条&#xff1a;了解Objective-C语言的起源第2条&#xff1a;在类的头文件中尽量少引入其他头文件第3条&#xff1a;多用字面量语法&#xff0c;少用与之等价的方法第4条&#xff1a;多用类型常量&#xff0c;少用#define预处理指令第…

社交网络安全:保护用户数据的Facebook实践

在数字化时代&#xff0c;社交网络安全成为了人们关注的焦点之一。作为全球最大的社交平台之一&#xff0c;Facebook一直在致力于保护用户数据安全和隐私。本文将探讨Facebook在社交网络安全方面的实践&#xff0c;以及它所采取的措施来保护用户数据的安全性。 1. 数据加密与隐…

AC/DC电源模块:适用于各种功率需求的电子设备

BOSHIDA AC/DC电源模块&#xff1a;适用于各种功率需求的电子设备 AC/DC电源模块是一种广泛应用于不同电子设备中的电源转换模块。它具有输出稳定、高效率、可靠性强等特点&#xff0c;适用于各种功率需求的电子设备。在本文中&#xff0c;我们将探讨AC/DC电源模块的工作原理…

亚信安慧AntDB数据库采集技术创新:ACC从Java到Go的转型之路

传统的指标采集方法通常使用一些命令行工具&#xff0c;如top、free等来获取系统的性能数据。然而&#xff0c;这种方法存在一些缺点。首先&#xff0c;这些命令行工具输出的数据格式通常是文本形式&#xff0c;需要进行解析和处理才能得到有用的信息&#xff0c;这增加了开发者…

计算机网络-BGP概述

一、概述 到目前为止我们已经学习了静态路由、OSPF、RIP、IS-IS了&#xff0c;前面我们也了解到按照区域或者范围来分&#xff0c;路由协议可以划分为&#xff1a;IGP内部网关协议、EGP外部网关协议&#xff0c;而我们前面学习的动态路由都属于IGP的范畴. IGP是用于单一自治系统…

科技赋能,拓宽生活边界

在当今多元化与快速变化的社会中&#xff0c;社会适应能力成为了衡量个人能否顺利融入社会、享受生活品质的关键指标。对于盲人朋友而言&#xff0c;这一能力尤为重要&#xff0c;它不仅关乎日常生活的便利&#xff0c;更影响到心理的健康与社会参与度。在此背景下&#xff0c;…

el-upload上传图片,视频可获取视频时长。

对element-ui组件的upload组件再一次封装&#xff0c;简单记录。下面是效果图。 注意点&#xff1a;该组件现在仅支持单图和单个视频上传。 <template><div :style"myStyle"><divclass"uploads":style"{width: upWith px,height: up…

代码随想录算法训练营第36期DAY36

贪心好难&#xff0c;希望能坚持到柳暗花明那天。 DAY36 1005K次取反后最大化的数组和 自己的方法&#xff0c;注意越界条件放在最前面就好&#xff1a; class Solution {public: int largestSumAfterKNegations(vector<int>& nums, int k) { //自己的…