图片传输 并且进行 zip 优化 时间

最开始 使用的是传统的方式,   使用的 是 InputStream 里面的  read

使用Input Strem  进行读取,  花了121 s

 //use InputStream to zip file in 121s file size is 3.19MB * 10
    void zipFile() {
        long begin = System.currentTimeMillis();
        File file = new File(zipFile);

        try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(file))) {
            for (int i = 0; i < 10; i++) {
                System.out.println("compress at " + i + " time");
                try (InputStream inputStream = new FileInputStream(JPG_FILE)) {
                    zip.putNextEntry(new ZipEntry("FILE_NAME" + i));
                    int temp = 0;
                    while ((temp = inputStream.read()) != -1) {
                        zip.write(temp);
                    }
                }
            }
            System.out.println("consumer time is " + (System.currentTimeMillis() - begin));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

使用了Bufferr 进行读取

Buffer 会比InputStream 快很多, 因为我们使用了缓冲区.

不会像之前的 read  那样一次只读一个Byte

 //use Buffer to read   to zip file in 2.5s file size is 3.19MB * 10
    void bufferZipFile() {
        long begin = System.currentTimeMillis();
        File file = new File(zipFile);
        try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(file));
             BufferedOutputStream outputStream = new BufferedOutputStream(zip)) {
            for (int i = 0; i < 10; i++) {
                System.out.println("compress at " + i + " time");
                try(BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(JPG_FILE))){
                    zip.putNextEntry(new ZipEntry("File_name" + i));
                    int temp = 0;
                    while((temp = inputStream.read()) != -1){
                        outputStream.write(temp);
                    }
                }
            }
            System.out.println("consumer time is " + (System.currentTimeMillis() - begin));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

使用了NIO 的channel  进行优化

channel 是使用了NIO 的操作系统模型, 会跟接近操作系统的习惯方式.,

 //use Channel  to read   to zip file in 1.5s file size is 3.19MB * 10
    void channelZipFile() {
        long begin = System.currentTimeMillis();
        File file = new File(zipFile);
        try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(file));
            WritableByteChannel channel = Channels.newChannel(zip)) {
            for (int i = 0 ; i < 10 ; i ++) {
                System.out.println("compress at " + i + " time");
                try(FileChannel fileChannel = new FileInputStream(JPG_FILE).getChannel()){
                    zip.putNextEntry(new ZipEntry("File_name" + i));
                    fileChannel.transferTo(0, 3 * 1000 * 1000, channel);
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("consumer time is " + (System.currentTimeMillis() - begin));
    }

总结:

为什么Buffer  缓存区 会比 慢慢读取要快很多呢?

因为这个就涉及到我们操作系统的 用户态和内核态了,

我们的应用程序都是属于用户态, 所以 当我们调用read  方法的时候 可以看到其实最后调用的是native 方法 read0.

    /**
     * Reads a byte of data from this input stream. This method blocks
     * if no input is yet available.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             file is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read() throws IOException {
        return read0();
    }

    private native int read0() throws IOException;

而我们应用程序想要使用操作系统里面的操作, 就得使用操作系统对外的接口, 这样我们就可以 将我们的线程从 用户态 变到 内核态.

所以再使用inputstream.read 方法的时候, 时间会特别耗时.

然而当我们使用Buffer(缓冲区)的时候, 这个时候系统会自动给我们创建一个映射区, 这时候, 我们只用再映射区中找对应的文件就好.

然后为什么NIO 的channel  的速度又有了些提升呢?

     * <p> This method does not modify this channel's position.  If the given
     * position is greater than the file's current size then no bytes are
     * transferred.  If the target channel has a position then bytes are
     * written starting at that position and then the position is incremented
     * by the number of bytes written.
     *
     * <p> This method is potentially much more efficient than a simple loop
     * that reads from this channel and writes to the target channel.  Many
     * operating systems can transfer bytes directly from the filesystem cache
     * to the target channel without actually copying them.  </p>

上面是channel transfer to 方法的注释, 上面说transferto 是直接写入到目标的channel 中, 而 没有copy 的过程 所以速度会更快一些.

用直接缓存区的缺点:

1. 不安全

2. 内存消耗增大 开辟的内存空间不由应用程序控制, 什么时候回收, 依赖于垃圾回收机.

3.控制, 当内容写入缓存区的时候, 应用程序就失去了对内容的控制, 这样子什么时候写入到文件中, 我们是没有办法进行控制的.

原文地址:https://www.cnblogs.com/mythdoraemon/p/12120166.html