NIO拷贝文件真的比IO拷贝文件效率高?

Wesley13
• 阅读 486

本文是基于单线程的NIO和IO拷贝文件比较, 并未对并发做测试, 请勿过度纠结场景!

今天发现项目中有个FileUtils.copy的工具方法, 打开后发现是基于io的, 我给改成了基于NIO的, 突然疑虑NIO拷贝文件真的如其他人说的那样比IO效率高很多么?

以下是我的工具方法:

/**
     * 
     * <p>通过NIO进行文件拷贝</p>
     * @param fromFile    被拷贝的文件
     * @param toFile    拷贝后的文件
     * @throws IOException 
     */
    public static void copy(String fromFile, String toFile) throws IOException {
        FileInputStream inputStream = new FileInputStream(fromFile);
        FileChannel fromChannel = inputStream.getChannel();
        
        FileOutputStream outputStream = new FileOutputStream(toFile);
        FileChannel toChannel   = outputStream.getChannel();
        
        toChannel.transferFrom(fromChannel, 0, fromChannel.size());
//        fromChannel.transferTo(0, fromChannel.size(), toChannel);
        
        toChannel.force(true);
        inputStream.close();
        fromChannel.close();
        outputStream.close();
        toChannel.close();
    }
    
    /**
     * 
     * <p>使用IO拷贝文件</p>
     * @param fromFile        被拷贝的文件
     * @param toFile        拷贝后的文件
     * @throws IOException
     */
    public static void copyByIO(String fromFile, String toFile) throws IOException {
        File inputFile = new File(fromFile);
        File outputFile = new File(toFile);
        FileInputStream inputStream = new FileInputStream(inputFile);
        FileOutputStream outputStream = new FileOutputStream(outputFile);
        byte[] bytes = new byte[1024];
        int c;
        while ((c = inputStream.read(bytes)) != -1)
            outputStream.write(bytes, 0, c);
        inputStream.close();
        outputStream.close();
    }

以下是测试方法:

@Test
    //8.72M文本文件-->拷贝100次: 8781        1000次:101564
    //4.65G压缩包同文件夹拷贝1次:136160        跨盘拷贝1次:147363    
    public void testCopyNIO() {
        String from = "d:/test/test.zip";
        Long start = System.currentTimeMillis();
        try {
            for(int i=0;i<1;i++) {
                String to   = "e:/test/test"+i+".zip";
                FileUtils.copy(from, to);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        Long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

    @Test
    //8.72M文本文件-->拷贝100次: 7719        1000次:109051
    //4.65G压缩包同文件夹拷贝1次:103261        跨盘拷贝1次:76799
    public void testCopyIO() {
        String from = "d:/test/test.zip";
        Long start = System.currentTimeMillis();
        try {
            for(int i=0;i<1;i++) {
                String to   = "e:/test/test"+i+".zip";
                FileUtils.copyByIO(from, to);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        Long end = System.currentTimeMillis();
        System.out.println(end-start);
    } 

第一次我找了个sysbase通过bcp命令导出的数据文件, 大小为8718KB, 使用以上两个测试方法, 分别拷贝了100次, 发现NIO执行时间为8781毫秒,IO执行时间为7719毫秒, NIO输了。

第二次我将拷贝次数改成了1000, 发现NIO执行时间为101564毫秒,IO执行时间为109051毫秒, NIO赢了, 但也仅仅赢了不到8秒。

第三次我将数据文件复制打包再复制再打包最后做出一个4,650,673KB大小的压缩包, 由于磁盘空间问题, 这次我只执行了1次, 发现NIO执行时间为136160毫秒,IO执行时间为103261毫秒, NIO输了33秒。

我又怀疑同一个文件夹下面拷贝可能没有突出NIO的优势,于是我又做了第四次测试, 换了个磁盘, 结果发现NIO执行时间为147363毫秒,IO执行时间为76799毫秒, NIO输了更惨, 耗费时间足足是IO的两倍。

可见NIO虽然在很多方面比IO强,但是这也并不是绝对的。

以上只是针对NIO和普通IO的简单测试, 并没有深究文件拷贝, 有兴趣的兄弟可以去研究下通过BufferedInputStream和RandomAccessFile来进行文件拷贝。其中RandomAccessFile效率应该和FileInputStream差不多, BufferedInputStream肯定比其他的要高效很多。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java 复制Map对象(深拷贝与浅拷贝)
java复制Map对象(深拷贝与浅拷贝)CreationTime2018年6月4日10点00分Author:Marydon1.深拷贝与浅拷贝  浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这