• 文件拷贝, 使用 BIO,NIO的对比,四种写法性能分析。


    测试环境: jdk 1.7 +  2G内存

    测试代码基本上复制了: http://blog.csdn.net/tabactivity/article/details/9317143

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    package test;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
     
    import java.io.FileInputStream;
     
    import java.io.FileOutputStream;
     
    import java.nio.MappedByteBuffer;
     
    import java.nio.channels.FileChannel;
     
    public class FileCopyTest
    {
     
        public FileCopyTest()
        {
            File[] files = new File("c:/images").listFiles();
            String destFolderPath = "g:/images";
     
            long t = System.currentTimeMillis();
     
            try
            {
                for (File sourceFile : files)
                {
                    traditionalCopy(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());
                }
     
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            System.out.println("传统IO方法实现文件拷贝耗时:" + (System.currentTimeMillis() - t) + "ms");
     
            //删除刚刚创建的
            for (File file : new File(destFolderPath).listFiles())
            {
                file.delete();
            }
     
            t = System.currentTimeMillis();
            try
            {
                for (File sourceFile : files)
                {
                    copyBIO(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());
                }
     
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            System.out.println("传统IO + 缓存 方法实现文件拷贝耗时:" + (System.currentTimeMillis() - t) + "ms");
     
            //删除刚刚创建的
            for (File file : new File(destFolderPath).listFiles())
            {
                file.delete();
            }
     
            t = System.currentTimeMillis();
            try
            {
                for (File sourceFile : files)
                {
                    nioCopy(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            System.out.println("利用NIO文件通道方法实现文件拷贝耗时:" + (System.currentTimeMillis() - t) + "ms");
     
            //删除刚刚创建的
            for (File file : new File(destFolderPath).listFiles())
            {
                file.delete();
            }
     
            t = System.currentTimeMillis();
            try
            {
                for (File sourceFile : files)
                {
                    nioCopy2(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            System.out.println("利用NIO文件内存映射及文件通道实现文件拷贝耗时:" + (System.currentTimeMillis() - t) + "ms");
     
            //删除刚刚创建的
            for (File file : new File(destFolderPath).listFiles())
            {
                file.delete();
            }
     
        }
     
        private static void traditionalCopy(String sourcePath, String destPath) throws Exception
        {
            File source = new File(sourcePath);
            File dest = new File(destPath);
     
            FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(dest);
             
            byte[] buf = new byte[8192];
            int len = 0;
     
            while ((len = fis.read(buf)) != -1)
            {
                fos.write(buf, 0, len);
            }
     
            fis.close();
            fos.close();
        }
     
        private static void copyBIO(String sourcePath, String destPath) throws Exception
        {
            File source = new File(sourcePath);
            File dest = new File(destPath);
     
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));
     
            byte[] buf = new byte[8192];
            int len = 0;
            while ((len = bis.read(buf)) != -1)
            {
                bos.write(buf, 0, len);
            }
     
            bis.close();
            bos.close();
        }
     
        private static void nioCopy(String sourcePath, String destPath) throws Exception
        {
            File source = new File(sourcePath);
            File dest = new File(destPath);
     
            FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(dest);
     
            FileChannel sourceCh = fis.getChannel();
            FileChannel destCh = fos.getChannel();
     
            destCh.transferFrom(sourceCh, 0, sourceCh.size());
     
            sourceCh.close();
            destCh.close();
     
        }
     
        private static void nioCopy2(String sourcePath, String destPath) throws Exception
        {
            File source = new File(sourcePath);
            File dest = new File(destPath);
     
            FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(dest);
     
            FileChannel sourceCh = fis.getChannel();
            FileChannel destCh = fos.getChannel();
     
            MappedByteBuffer mbb = sourceCh.map(FileChannel.MapMode.READ_ONLY, 0, sourceCh.size());
     
            destCh.write(mbb);
     
            sourceCh.close();
            destCh.close();
        }
     
    }

    测试结果有些地方还是感到意外:

    复制到同一块硬盘的其他分区, 总文件大小: 33M,其中一个文件:16M

    -----------------------------------------------------------------------------

    传统IO方法实现文件拷贝耗时:1156ms

    传统IO + 缓存 方法实现文件拷贝耗时:1312ms

    利用NIO文件通道方法实现文件拷贝耗时:1109ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:891ms

    传统IO方法实现文件拷贝耗时:1157ms

    传统IO + 缓存 方法实现文件拷贝耗时:1312ms

    利用NIO文件通道方法实现文件拷贝耗时:1078ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:891ms

    传统IO方法实现文件拷贝耗时:1203ms

    传统IO + 缓存 方法实现文件拷贝耗时:1172ms

    利用NIO文件通道方法实现文件拷贝耗时:1157ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:891ms

    传统IO方法实现文件拷贝耗时:984ms

    传统IO + 缓存 方法实现文件拷贝耗时:984ms

    利用NIO文件通道方法实现文件拷贝耗时:1172ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:938ms

    复制到另一个硬盘, 总文件大小: 33M,其中一个文件:16M

    -----------------------------------------------------------------------------

    传统IO方法实现文件拷贝耗时:1110ms

    传统IO + 缓存 方法实现文件拷贝耗时:1343ms

    利用NIO文件通道方法实现文件拷贝耗时:984ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:937ms

    传统IO方法实现文件拷贝耗时:985ms

    传统IO + 缓存 方法实现文件拷贝耗时:1516ms

    利用NIO文件通道方法实现文件拷贝耗时:1203ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:890ms

    传统IO方法实现文件拷贝耗时:875ms

    传统IO + 缓存 方法实现文件拷贝耗时:1203ms

    利用NIO文件通道方法实现文件拷贝耗时:1391ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:1031ms

    传统IO方法实现文件拷贝耗时:938ms

    传统IO + 缓存 方法实现文件拷贝耗时:1266ms

    利用NIO文件通道方法实现文件拷贝耗时:1453ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:968ms

    复制到另一个硬盘, 总文件大小: 81M,其中一个文件:66M

    -----------------------------------------------------------------------------

    传统IO方法实现文件拷贝耗时:4812ms

    传统IO + 缓存 方法实现文件拷贝耗时:6250ms

    利用NIO文件通道方法实现文件拷贝耗时:3375ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:3453ms

    传统IO方法实现文件拷贝耗时:5328ms

    传统IO + 缓存 方法实现文件拷贝耗时:6110ms

    利用NIO文件通道方法实现文件拷贝耗时:3766ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:3641ms

    复制到移动硬盘(用了3年), 总文件大小: 33M,其中一个文件:16M

    -----------------------------------------------------------------------------

    传统IO方法实现文件拷贝耗时:16532ms

    传统IO + 缓存 方法实现文件拷贝耗时:15828ms

    利用NIO文件通道方法实现文件拷贝耗时:34437ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:34797ms

    传统IO方法实现文件拷贝耗时:20672ms

    传统IO + 缓存 方法实现文件拷贝耗时:19547ms

    利用NIO文件通道方法实现文件拷贝耗时:33844ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:33375ms

    复制到移动硬盘(用了3年), 总文件大小: 15M,单个文件:150KB左右。

    -----------------------------------------------------------------------------

    传统IO方法实现文件拷贝耗时:172ms

    传统IO + 缓存 方法实现文件拷贝耗时:157ms

    利用NIO文件通道方法实现文件拷贝耗时:188ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:313ms

    传统IO方法实现文件拷贝耗时:156ms

    传统IO + 缓存 方法实现文件拷贝耗时:156ms

    利用NIO文件通道方法实现文件拷贝耗时:188ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:344ms

    传统IO方法实现文件拷贝耗时:203ms

    传统IO + 缓存 方法实现文件拷贝耗时:218ms

    利用NIO文件通道方法实现文件拷贝耗时:187ms

    利用NIO文件内存映射及文件通道实现文件拷贝耗时:282ms

    总结:

    1. 根据上面的测试结果表明,如果拷贝的是小文件(单个文件几百KB),使用NIO并不会比IO快.

    如果拷贝的单个文件达到几十M+,使用NIO速度会快的比较明显。

    2. 测试时还发现 traditionalCopy()无论处理小文件还是大文件都不比copyBIO()慢。

    traditionalCopy()就是使用最基本的 FileInputStream 和 FileOutStream。

    copyBIO()使用的是BufferedInputStream 和 BufferedOutputStream。

    关于这一点,可能是因为 “从1.5开始,Java对InputStream/OutputStream 进行了重新改写,用的就是NIO,因此,就算你不显示声明要用NIO,只要你的类继承了InputStream/OutputStream就已经在用NIO了”

    参考资料: http://zhidao.baidu.com/question/109313742.html

    3. 测试拷贝到移动硬盘上时,使用传统的IO比NIO速度还快,并且快很多。(这块移动硬盘用了3年,写入速度不怎么样)

    这个原因我无法解释,有谁能告诉我?

    2014-03-02

  • 相关阅读:
    笔试题系列001
    算法系列001---dfs|多叉|解空间树理解
    leetcode--014 Gas station
    leetcode--012 single number I
    leetcode--011 copy list with random pointer
    leetcode--010 Linked List Cycle II
    leetcode--009 Linked List Cycle I
    leetcode--007 word break I
    leetcode-006 detect cycle
    alex鸡汤回信
  • 原文地址:https://www.cnblogs.com/personnel/p/4584919.html
Copyright © 2020-2023  润新知