在软件系统中,IO速度比内存速度慢,IO读写在很多情况下会是系统的瓶颈。
在java标准IO操作中,InputStream和OutputStream提供基于流的IO操作,以字节为处理单位;Reader和Writer实现了Buffered缓存,以字符为处理单位。
从Java1.4开始,增加NIO(New IO),增加缓存Buffer和通道Channel,以块为处理单位,是双向通道(可读可写,类似RandomAccessFile),支持锁和内存映射文件访问接口,大大提升了IO速度。
以下例子简单测试常见IO操作的性能速度。
- /**
- * 测试不同io操作速度
- *
- * @author peter_wang
- * @create-time 2014-6-4 下午12:52:48
- */
- public class SpeedTest {
- private static final String INPUT_FILE_PATH = "io_speed.txt";
- private static final String OUTPUT_FILE_PATH = "io_speed_copy.txt";
- /**
- * @param args
- */
- public static void main(String[] args) {
- long ioStreamTime1 = ioStreamCopy();
- System.out.println("io stream copy:" + ioStreamTime1);
- long ioStreamTime2 = bufferedStreamCopy();
- System.out.println("buffered stream copy:" + ioStreamTime2);
- long ioStreamTime3 = nioStreamCopy();
- System.out.println("nio stream copy:" + ioStreamTime3);
- long ioStreamTime4 = nioMemoryStreamCopy();
- System.out.println("nio memory stream copy:" + ioStreamTime4);
- }
- /**
- * 普通文件流读写
- *
- * @return 操作的时间
- */
- private static long ioStreamCopy() {
- long costTime = -1;
- FileInputStream is = null;
- FileOutputStream os = null;
- try {
- long startTime = System.currentTimeMillis();
- is = new FileInputStream(INPUT_FILE_PATH);
- os = new FileOutputStream(OUTPUT_FILE_PATH);
- int read = is.read();
- while (read != -1) {
- os.write(read);
- read = is.read();
- }
- long endTime = System.currentTimeMillis();
- costTime = endTime - startTime;
- }
- catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- finally {
- try {
- if (is != null) {
- is.close();
- }
- if (os != null) {
- os.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- return costTime;
- }
- /**
- * 加入缓存的文件流读写, Reader默认实现缓存,只能读取字符文件,无法准确读取字节文件如图片视频等
- *
- * @return 操作的时间
- */
- private static long bufferedStreamCopy() {
- long costTime = -1;
- FileReader reader = null;
- FileWriter writer = null;
- try {
- long startTime = System.currentTimeMillis();
- reader = new FileReader(INPUT_FILE_PATH);
- writer = new FileWriter(OUTPUT_FILE_PATH);
- int read = -1;
- while ((read = reader.read()) != -1) {
- writer.write(read);
- }
- writer.flush();
- long endTime = System.currentTimeMillis();
- costTime = endTime - startTime;
- }
- catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- finally {
- try {
- if (reader != null) {
- reader.close();
- }
- if (writer != null) {
- writer.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- return costTime;
- }
- /**
- * nio操作数据流
- *
- * @return 操作的时间
- */
- private static long nioStreamCopy() {
- long costTime = -1;
- FileInputStream is = null;
- FileOutputStream os = null;
- FileChannel fi = null;
- FileChannel fo = null;
- try {
- long startTime = System.currentTimeMillis();
- is = new FileInputStream(INPUT_FILE_PATH);
- os = new FileOutputStream(OUTPUT_FILE_PATH);
- fi = is.getChannel();
- fo = os.getChannel();
- ByteBuffer buffer = ByteBuffer.allocate(1024);
- while (true) {
- buffer.clear();
- int read = fi.read(buffer);
- if (read == -1) {
- break;
- }
- buffer.flip();
- fo.write(buffer);
- }
- long endTime = System.currentTimeMillis();
- costTime = endTime - startTime;
- }
- catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- finally {
- try {
- if (fi != null) {
- fi.close();
- }
- if (fo != null) {
- fo.close();
- }
- if (is != null) {
- is.close();
- }
- if (os != null) {
- os.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- return costTime;
- }
- /**
- * nio内存映射操作数据流
- *
- * @return 操作的时间
- */
- private static long nioMemoryStreamCopy() {
- long costTime = -1;
- FileInputStream is = null;
- //映射文件输出必须用RandomAccessFile
- RandomAccessFile os = null;
- FileChannel fi = null;
- FileChannel fo = null;
- try {
- long startTime = System.currentTimeMillis();
- is = new FileInputStream(INPUT_FILE_PATH);
- os = new RandomAccessFile(OUTPUT_FILE_PATH, "rw");
- fi = is.getChannel();
- fo = os.getChannel();
- IntBuffer iIb=fi.map(FileChannel.MapMode.READ_ONLY, 0, fi.size()).asIntBuffer();
- IntBuffer oIb = fo.map(FileChannel.MapMode.READ_WRITE, 0, fo.size()).asIntBuffer();
- while(iIb.hasRemaining()){
- int read = iIb.get();
- oIb.put(read);
- }
- long endTime = System.currentTimeMillis();
- costTime = endTime - startTime;
- }
- catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- finally {
- try {
- if (fi != null) {
- fi.close();
- }
- if (fo != null) {
- fo.close();
- }
- if (is != null) {
- is.close();
- }
- if (os != null) {
- os.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- return costTime;
- }
- }
运行结果:
- io stream copy:384
- buffered stream copy:125
- nio stream copy:12
- nio memory stream copy:10
结论分析:
最普通的InputStream操作耗时较长,增加了缓存后速度增加了,用了nio和内存映射访问文件,速度最快。