美文网首页Java学习笔记程序员
java 四种io实现速度对比

java 四种io实现速度对比

作者: 徐士林 | 来源:发表于2017-03-02 00:05 被阅读571次
import java.io.*;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class SpeedTest {
    private static final String INPUT_FILE_PATH = "io_speed.pdf";
    private static final String OUTPUT_FILE_PATH = "io_speed_copy.pdf";

    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);
    }

    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;
    }

    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;
    }

    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;
    }

    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;
    }
}

程序来源

复制大小约90MB的文件所需的时间(单位:毫秒)

io stream copy:182797
buffered stream copy:14699
nio stream copy:1251
nio memory stream copy:884

很显然传统的IO方式效率很低,甚至于差了nio两个数量级。nio内存映射访问速度最快。

java I/O的工作机制

data-buffering-at-os-level.png

上图很简单的显示了数据传输的指示图,当应用进程执行到read()操作时操作系统底层一下操作

  1. 内核通知DMA读取某块数据
  2. 磁盘控制器通过DMA将数据读入到内核的缓冲区
  3. 当缓冲完成是,内核会把数据从内核缓冲区读到进程指定缓冲区。

这一系列操作涉及到底层调用,而jvm进程属于用户进程,一旦涉及到系统调用就会从用户态切换到内核态。这个切换也是一个相当耗时的操作。

其实还有比较重要的是,用户进程一次读取一个字节或者读到一个字节数组中,但是内核通过磁盘控制器一般是读取某一块或者是某几块的数据。
不然每次都进如内核态不是一个很愚蠢的事情呒?所以第一次read()的时候会访问到磁盘数据,后续可能直接从内核缓冲中拿数据。

如果数据不可用,process将会被挂起,并需要等待内核从磁盘上把数据取到内核缓冲区中。

由于DMA不能直接访问用户空间(用户缓冲区),普通IO操作需要将数据来回地在 用户缓冲区 和 内核缓冲区移动,这在一定程序上影响了IO的速度,并且这是一种阻塞式的数据读取方式,并不能很有效的利用cpu。

而java io流中的缓冲流输入输出时都会把数据储存一个数组中,也就是进程的缓冲区(默认是8192字节),这样就可以等数据满了以后一次性切换到内核态并写入磁盘,相比于io流的多次切换到内核态,90M的文件读写就可以提升一个数量级了。

IO 是基于流来读取的,而NIO则是基于块读取,面向流 的 I/O 系统一次一个字节地处理数据。 面向块 的 I/O 系统以块的形式处理数据。按块处理数据比按(流式的)字节处理数据要快得多。 所以NIO通过buffer和channel读取数据又要比IO流快上一个数量级。并且 NIO 支持 Direct Memory, 可以减少一次数据拷贝。可见通过FileChannel读取数据还是有很大优势的,并且NIO可以通过selector实现异步读取的操作。

那么速度最快的内存映射又是什么呢?


715283-20160804114034684-1256880404.png

首先NIO提供了内存映射或者说是直接内存,这可以使得数据少一次数据的拷贝,又可以节省大量时间。

内核空间和用户空间会映射到同一块物理内存,这样减少一次数据的拷贝,所以这种方式的文件操作速度会非常快(和文件大小也有关系,并没有绝对好的方式)
MappedByteBuffer可以通过java.nio.channels.FileChannel的 map方法创建。具体关于MappedByteBuffer还是可以在写一篇博客详细论述的。

这一篇就到这吧,写的越多发现自己不会的就越多,以后再写博客来填了这些坑吧

参考

相关文章

  • java 四种io实现速度对比

    程序来源 复制大小约90MB的文件所需的时间(单位:毫秒) io stream copy:182797buffer...

  • Java中的IO模型

    Java中的IO模型 Java中的IO模型有四种: 同步阻塞IO 同步非阻塞IO IO多路复用 异步IO 其中IO...

  • JAVAIO-FileOutputStream

    java.io.FileOutputStream是java.io.OutputStream的具体实现,提供连接到文...

  • java IO入门笔记

    1.java IO流的概念,分类,类图 1.1. java IO 流的概念 java的io是实现输入和输出的基础,...

  • Java IO详解

    1 Java IO流的概念,分类 1.1 Java IO流的概念 java的IO是实现输入和输出的基础,可以方便的...

  • NIO你真正了解多少?

    解释一下java.io.Serializable接口 类通过实现 Java.io.Serializable 接口以...

  • IO

    Java io和Linux io有什么对应关系?java在部署在平台上很多实现依赖平台的API。高效实现如:rea...

  • 梳理二

    1、java四种引用类型 https://longfeizheng.github.io/2018/04/09/Ja...

  • Java实现文件目录操作书目录

    Java实现文件目录操作之使用IO和NIO创建目录 Java实现文件目录操作之递归遍历目录和文件 Java实现文件...

  • Android Review

    java相关 java基础面试题 四种引用对比 List,Set,Map 详解 反射 JNI JNI 各版本特性 ...

网友评论

    本文标题:java 四种io实现速度对比

    本文链接:https://www.haomeiwen.com/subject/pxwcgttx.html