在软件系统中,IO速度比内存速度慢,IO读写在很多情况下会是系统的瓶颈。
在java标准IO操作中,InputStream和OutputStream提供基于流的IO操作,以字节为处理单位;Reader和Writer实现了Buffered缓存,以字符为处理单位。
从Java1.4开始,增加NIO(New IO),增加缓存Buffer和通道Channel,以块为处理单位,是双向通道(可读可写,类似RandomAccessFile),支持锁和内存映射文件访问接口,大大提升了IO速度。
以下例子简单测试常见IO操作的性能速度。
1 import java.io.*; 2 import java.nio.ByteBuffer; 3 import java.nio.IntBuffer; 4 import java.nio.channels.FileChannel; 5 6 /** 7 * Created by yubo10581 on 2016/1/28. 8 */ 9 public class fileSpeedTest { 10 private static final String INPUT_FILE_PATH = "E:/IdeaProjects/theFirstProject/testOne/testFile/io_speed.txt"; 11 private static final String OUTPUT_FILE_PATH = "E:/IdeaProjects/theFirstProject/testOne/testFile/io_speed_copy.txt"; 12 13 public static void main(String[] args) { 14 long ioStreamCopyTime = ioStreamCopy(); 15 System.out.println("io stream copy:" + ioStreamCopyTime+"ms"); 16 17 long bufferedStreamTime = bufferedStreamCopy(); 18 System.out.println("buffered stream copy:" + bufferedStreamTime+"ms"); 19 20 long nioStreamTime = nioStreamCopy(); 21 System.out.println("nio stream copy:" + nioStreamTime+"ms"); 22 23 long nioMemoryStreamTime = nioMemoryStreamCopy(); 24 System.out.println("nio memory stream copy:" + nioMemoryStreamTime+"ms"); 25 26 } 27 28 /** 29 * 普通文件流读写 30 * 31 * @return 操作的时间 32 */ 33 private static long ioStreamCopy() { 34 long costTime = -1; 35 FileInputStream is = null; 36 FileOutputStream os = null; 37 try { 38 long startTime = System.currentTimeMillis(); 39 is = new FileInputStream(INPUT_FILE_PATH); 40 os = new FileOutputStream(OUTPUT_FILE_PATH); 41 int read = is.read(); 42 while (read != -1) { 43 os.write(read); 44 read = is.read(); 45 } 46 long endTime = System.currentTimeMillis(); 47 costTime = endTime - startTime; 48 } 49 catch (FileNotFoundException e) { 50 e.printStackTrace(); 51 } 52 catch (IOException e) { 53 e.printStackTrace(); 54 } 55 finally { 56 try { 57 if (is != null) { 58 is.close(); 59 } 60 if (os != null) { 61 os.close(); 62 } 63 } 64 catch (IOException e) { 65 e.printStackTrace(); 66 } 67 } 68 return costTime; 69 } 70 71 /** 72 * 加入缓存的文件流读写, Reader默认实现缓存,只能读取字符文件,无法准确读取字节文件如图片视频等 73 * 74 * @return 操作的时间 75 */ 76 private static long bufferedStreamCopy() { 77 long costTime = -1; 78 FileReader reader = null; 79 FileWriter writer = null; 80 try { 81 long startTime = System.currentTimeMillis(); 82 reader = new FileReader(INPUT_FILE_PATH); 83 writer = new FileWriter(OUTPUT_FILE_PATH); 84 int read = -1; 85 while ((read = reader.read()) != -1) { 86 writer.write(read); 87 } 88 writer.flush(); 89 long endTime = System.currentTimeMillis(); 90 costTime = endTime - startTime; 91 } 92 catch (FileNotFoundException e) { 93 e.printStackTrace(); 94 } 95 catch (IOException e) { 96 e.printStackTrace(); 97 } 98 finally { 99 try { 100 if (reader != null) { 101 reader.close(); 102 } 103 if (writer != null) { 104 writer.close(); 105 } 106 } 107 catch (IOException e) { 108 e.printStackTrace(); 109 } 110 } 111 return costTime; 112 } 113 114 /** 115 * nio操作数据流 116 * 117 * @return 操作的时间 118 */ 119 private static long nioStreamCopy() { 120 long costTime = -1; 121 FileInputStream is = null; 122 FileOutputStream os = null; 123 FileChannel fi = null; 124 FileChannel fo = null; 125 try { 126 long startTime = System.currentTimeMillis(); 127 is = new FileInputStream(INPUT_FILE_PATH); 128 os = new FileOutputStream(OUTPUT_FILE_PATH); 129 fi = is.getChannel(); 130 fo = os.getChannel(); 131 ByteBuffer buffer = ByteBuffer.allocate(1024); 132 while (true) { 133 buffer.clear(); 134 int read = fi.read(buffer); 135 if (read == -1) { 136 break; 137 } 138 buffer.flip(); 139 fo.write(buffer); 140 } 141 long endTime = System.currentTimeMillis(); 142 costTime = endTime - startTime; 143 } 144 catch (FileNotFoundException e) { 145 e.printStackTrace(); 146 } 147 catch (IOException e) { 148 e.printStackTrace(); 149 } 150 finally { 151 try { 152 if (fi != null) { 153 fi.close(); 154 } 155 if (fo != null) { 156 fo.close(); 157 } 158 if (is != null) { 159 is.close(); 160 } 161 if (os != null) { 162 os.close(); 163 } 164 } 165 catch (IOException e) { 166 e.printStackTrace(); 167 } 168 } 169 return costTime; 170 } 171 172 /** 173 * nio内存映射操作数据流 174 * 175 * @return 操作的时间 176 */ 177 private static long nioMemoryStreamCopy() { 178 long costTime = -1; 179 FileInputStream is = null; 180 //映射文件输出必须用RandomAccessFile 181 RandomAccessFile os = null; 182 FileChannel fi = null; 183 FileChannel fo = null; 184 try { 185 long startTime = System.currentTimeMillis(); 186 is = new FileInputStream(INPUT_FILE_PATH); 187 os = new RandomAccessFile(OUTPUT_FILE_PATH, "rw"); 188 fi = is.getChannel(); 189 fo = os.getChannel(); 190 IntBuffer iIb=fi.map(FileChannel.MapMode.READ_ONLY, 0, fi.size()).asIntBuffer(); 191 IntBuffer oIb = fo.map(FileChannel.MapMode.READ_WRITE, 0, fo.size()).asIntBuffer(); 192 while(iIb.hasRemaining()){ 193 int read = iIb.get(); 194 oIb.put(read); 195 } 196 long endTime = System.currentTimeMillis(); 197 costTime = endTime - startTime; 198 } catch (FileNotFoundException e) { 199 e.printStackTrace(); 200 } catch (IOException e) { 201 e.printStackTrace(); 202 } finally { 203 try { 204 if (fi != null) { 205 fi.close(); 206 } 207 if (fo != null) { 208 fo.close(); 209 } 210 if (is != null) { 211 is.close(); 212 } 213 if (os != null) { 214 os.close(); 215 } 216 } catch (IOException e) { 217 e.printStackTrace(); 218 } 219 } 220 return costTime; 221 } 222 223 }
最普通的InputStream操作耗时较长,增加了缓存后速度增加了,用了nio和内存映射访问文件,速度最快。