本文共 10067 字,大约阅读时间需要 33 分钟。
经过一组简单的测试发现JAVA NIO提供的文件内存映射方法实现文件拷贝速度最快,不管是大文件还是小文件,特别是大文件的拷贝速度比普通方法提高20倍,唯一有个前提就是内存需要足够大,否则文件映射肯定失败(当然可以通过分割文件,部分映射的方法避免,但就比较麻烦了);其次NIO提供的文件管道传输速度也比较好,如果没法做文件内存映射,推荐这种拷贝方法;另外,Buffer的大小,对于读写速度还是有影响的,基本就是Buffer越大读写越快(有个疑问就是Buffer.allocateDirec()效率提高不明显);最后,总体看来NIO的效率比老IO高,不管使用哪种方式,老IO使用流读写只能一个字节一个字节的抠,NIO使用块的方式读写还是相对比较快,所以没有特别需求的情况下,推荐使用NIO,目前NIO基本能覆盖老IO的所有功能(当然NIO还提供N多新功能)。
测试环境
1 2 3 4 5 6 7 8 9 | Eclipse(Juno) JVM(Sun JDK1. 7 ) 参数: -Xms1536m -Xmx1536m -Xverify:none -XX:+UseParallelGC -XX:PermSize=128M -XX:MaxPermSize=128M OS参数: Win7 64Bit + 4GB 物理磁盘空间充足 |
测试代码
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 185 186 187 188 189 190 | import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class FileCopy { private static final int BUFFER_SIZE_1024 = 1024 ; private static final int BUFFER_SIZE_4096 = 4096 ; private static final int BUFFER_SIZE_10240 = 10240 ; private static final String FROM_FILE_42MB = "G:/from_42MB.rar" ; private static final String FROM_FILE_1GB = "G:/from_350MB.rar" ; private static int BUFFER_SIZE = BUFFER_SIZE_1024; private static String FROM_FILE = FROM_FILE_42MB; /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { System.out.println( "File :" + FROM_FILE + " ---- Buffer Size : " + BUFFER_SIZE + "--------------" ); testFileCopy(); BUFFER_SIZE = BUFFER_SIZE_4096; System.out.println( "File :" + FROM_FILE + " ---- Buffer Size : " + BUFFER_SIZE + "--------------" ); testFileCopy(); BUFFER_SIZE = BUFFER_SIZE_10240; System.out.println( "File :" + FROM_FILE + " ---- Buffer Size : " + BUFFER_SIZE + "--------------" ); testFileCopy(); BUFFER_SIZE = BUFFER_SIZE_1024; FROM_FILE = FROM_FILE_1GB; System.out.println( "File :" + FROM_FILE + " ---- Buffer Size : " + BUFFER_SIZE + "--------------" ); testFileCopy(); BUFFER_SIZE = BUFFER_SIZE_4096; FROM_FILE = FROM_FILE_1GB; System.out.println( "File :" + FROM_FILE + " ---- Buffer Size : " + BUFFER_SIZE + "--------------" ); testFileCopy(); BUFFER_SIZE = BUFFER_SIZE_10240; FROM_FILE = FROM_FILE_1GB; System.out.println( "File :" + FROM_FILE + " ---- Buffer Size : " + BUFFER_SIZE + "--------------" ); testFileCopy(); } private static void testFileCopy() throws FileNotFoundException, IOException { coypByMbb(); copyByNioTransferFrom(); copyByNioTransferTo(); coypByBufferRead(); coypByFastBufferRead(); coypByStream(); //Old IO style } /** * 使用FileChannel.transferFrom()实现 * @throws FileNotFoundException * @throws IOException */ private static void copyByNioTransferFrom() throws FileNotFoundException, IOException { long startTime = System.currentTimeMillis(); RandomAccessFile fromFile = new RandomAccessFile(FROM_FILE, "rw" ); FileChannel fromChannel = fromFile.getChannel(); RandomAccessFile toFile = new RandomAccessFile( "G:/to1.rar" , "rw" ); FileChannel toChannel = toFile.getChannel(); long position = 0 ; long count = fromChannel.size(); toChannel.transferFrom(fromChannel, position, count); long endTime = System.currentTimeMillis(); System.out.println( "copyByNioTransferFrom time consumed(buffer size no effect) : " + (endTime - startTime)); } /** * 使用FileChannel.transferTo()实现 * @throws FileNotFoundException * @throws IOException */ private static void copyByNioTransferTo() throws FileNotFoundException, IOException { long startTime = System.currentTimeMillis(); RandomAccessFile fromFile = new RandomAccessFile(FROM_FILE, "rw" ); FileChannel fromChannel = fromFile.getChannel(); RandomAccessFile toFile = new RandomAccessFile( "G:/to2.rar" , "rw" ); FileChannel toChannel = toFile.getChannel(); long position = 0 ; long count = fromChannel.size(); fromChannel.transferTo(position, count, toChannel); long endTime = System.currentTimeMillis(); System.out.println( "copyByNioTransferTo time consumed(buffer size no effect) : " + (endTime - startTime)); } /** * 使用Channel, Buffer简单读写实现 * @throws IOException */ private static void coypByBufferRead() throws IOException { long startTime = System.currentTimeMillis(); FileInputStream fin = new FileInputStream(FROM_FILE); FileOutputStream fout = new FileOutputStream( "G:/to3.rar" ); FileChannel fcin = fin.getChannel(); FileChannel fcout = fout.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); while ( true ) { buffer.clear(); int r = fcin.read(buffer); if (r == - 1 ) { break ; } buffer.flip(); fcout.write(buffer); } long endTime = System.currentTimeMillis(); System.out.println( "coypByBufferRead time consumed(buffer size take effect) : " + (endTime - startTime)); } /** * 使用连续内存的Buffer实现 * @throws IOException */ private static void coypByFastBufferRead() throws IOException { long startTime = System.currentTimeMillis(); FileInputStream fin = new FileInputStream(FROM_FILE); FileOutputStream fout = new FileOutputStream( "G:/to4.rar" ); FileChannel fcin = fin.getChannel(); FileChannel fcout = fout.getChannel(); ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); while ( true ) { buffer.clear(); int r = fcin.read(buffer); if (r == - 1 ) { break ; } buffer.flip(); fcout.write(buffer); } long endTime = System.currentTimeMillis(); System.out.println( "coypByFastBufferRead time consumed(buffer size take effect) : " + (endTime - startTime)); } /** * 使用文件内存映射实现 * @throws IOException */ private static void coypByMbb() throws IOException { long startTime = System.currentTimeMillis(); FileInputStream fin = new FileInputStream(FROM_FILE); RandomAccessFile fout = new RandomAccessFile( "G:/to5.rar" , "rw" ); FileChannel fcin = fin.getChannel(); FileChannel fcout = fout.getChannel(); MappedByteBuffer mbbi = fcin.map(FileChannel.MapMode.READ_ONLY, 0 , fcin.size()); MappedByteBuffer mbbo = fcout.map(FileChannel.MapMode.READ_WRITE, 0 , fcin.size()); mbbo.put(mbbi); mbbi.clear(); mbbo.clear(); long endTime = System.currentTimeMillis(); System.out .println( "coypByMbb time consumed(buffer size no effect) : " + (endTime - startTime)); } /** * 使用传统IO的流读写方式实现 * @throws IOException */ private static void coypByStream() throws IOException { long startTime = System.currentTimeMillis(); FileInputStream fin = new FileInputStream(FROM_FILE); FileOutputStream fout = new FileOutputStream( "G:/to6.rar" ); byte [] buffer = new byte [BUFFER_SIZE]; while ( true ) { int ins = fin.read(buffer); if (ins == - 1 ) { fin.close(); fout.flush(); fout.close(); break ; } else { fout.write(buffer, 0 , ins); } } long endTime = System.currentTimeMillis(); System.out.println( "coypByStream time consumed(buffer size take effect) : " + (endTime - startTime)); } } |
测试结果
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 | File :G:/from_42MB.rar ---- Buffer Size : 1024 -------------- coypByMbb time consumed(buffer size no effect) : 47 copyByNioTransferFrom time consumed(buffer size no effect) : 62 copyByNioTransferTo time consumed(buffer size no effect) : 47 coypByBufferRead time consumed(buffer size take effect) : 249 coypByFastBufferRead time consumed(buffer size take effect) : 188 coypByStream time consumed(buffer size take effect) : 187 File :G:/from_42MB.rar ---- Buffer Size : 4096 -------------- coypByMbb time consumed(buffer size no effect) : 15 copyByNioTransferFrom time consumed(buffer size no effect) : 16 copyByNioTransferTo time consumed(buffer size no effect) : 31 coypByBufferRead time consumed(buffer size take effect) : 125 coypByFastBufferRead time consumed(buffer size take effect) : 79 coypByStream time consumed(buffer size take effect) : 93 File :G:/from_42MB.rar ---- Buffer Size : 10240 -------------- coypByMbb time consumed(buffer size no effect) : 16 copyByNioTransferFrom time consumed(buffer size no effect) : 32 copyByNioTransferTo time consumed(buffer size no effect) : 31 coypByBufferRead time consumed(buffer size take effect) : 78 coypByFastBufferRead time consumed(buffer size take effect) : 62 coypByStream time consumed(buffer size take effect) : 63 File :G:/from_350MB.rar ---- Buffer Size : 1024 -------------- coypByMbb time consumed(buffer size no effect) : 280 copyByNioTransferFrom time consumed(buffer size no effect) : 453 copyByNioTransferTo time consumed(buffer size no effect) : 7785 coypByBufferRead time consumed(buffer size take effect) : 8144 coypByFastBufferRead time consumed(buffer size take effect) : 7068 coypByStream time consumed(buffer size take effect) : 8503 File :G:/from_350MB.rar ---- Buffer Size : 4096 -------------- coypByMbb time consumed(buffer size no effect) : 1904 copyByNioTransferFrom time consumed(buffer size no effect) : 5978 copyByNioTransferTo time consumed(buffer size no effect) : 7379 coypByBufferRead time consumed(buffer size take effect) : 7621 coypByFastBufferRead time consumed(buffer size take effect) : 7474 coypByStream time consumed(buffer size take effect) : 8200 File :G:/from_350MB.rar ---- Buffer Size : 10240 -------------- coypByMbb time consumed(buffer size no effect) : 328 copyByNioTransferFrom time consumed(buffer size no effect) : 6864 copyByNioTransferTo time consumed(buffer size no effect) : 7021 coypByBufferRead time consumed(buffer size take effect) : 7199 coypByFastBufferRead time consumed(buffer size take effect) : 7941 coypByStream time consumed(buffer size take effect) : 7801 |