压缩文件,IO拷贝优化。

public class TestIO {
    public static void main(String[] args) {
        long beginTime = System.currentTimeMillis();
        String ZIP_FILE = "1023.zip";
        File zipFile = new File(ZIP_FILE);
        File src = new File("F:\\person_code\\jvm_deep_base\\module04\\src\\main\\java\\jdk1.8.0_291.zip");
        try (// 在这里声明资源,jdk1.7以后会自动关闭关闭资源
             ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
             InputStream inputStream = new FileInputStream(src);) {
             zipOut.putNextEntry(new ZipEntry("1023.zip"));
             int trans = 0;
             while ((trans = inputStream.read()) != -1) {
                zipOut.write(trans);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("文件大小: " + src.length());
        System.out.println("耗时: " + (System.currentTimeMillis() - beginTime));
    }
}

 使用字节输入输出流进行I/O拷贝,传输单位是一个字节,速度缓慢。

public class TestIO2 {
    public static void main(String[] args) {
        String ZIP_FILE = "1023.zip";
        File zipFile = new File(ZIP_FILE);
        File src = new File("F:\\person_code\\jvm_deep_base\\module04\\src\\main\\java\\jdk1.8.0_291.zip");
        long beginTime = System.currentTimeMillis();
        try (
             // jdk以后 这里声明的变量会自动关闭申请的资源
             ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOut);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));
            ) {
            zipOut.putNextEntry(new ZipEntry("1023.zip"));
            int trans = 0;
            while ((trans = bufferedInputStream.read()) != -1) {
               bufferedOutputStream.write(trans);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("文件大小: " + src.length());
        System.out.println("耗时: " + (System.currentTimeMillis() - beginTime));
    }
}

使用字节缓冲输入输出流进行I/O拷贝,传输单位是一个字节,速度缓慢。例如我们现在有30000个字节的数据,如果使用 FileInputStream那么就需要调用30000次的本地方法来获取这些数据,而如果使用缓冲区的话(这里假设初始的缓冲区大小足够放下30000字节的数据)那么只需要调用一次就行。

 

public class TestIO3 {
    public static void main(String[] args) {
        String ZIP_FILE = "1023.zip";
        File zipFile = new File(ZIP_FILE);
        File src = new File("F:\\person_code\\jvm_deep_base\\module04\\src\\main\\java\\jdk1.8.0_291.zip");
        long beginTime = System.currentTimeMillis();
        try (
                // jdk以后 这里声明的变量会自动关闭申请的资源
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
                WritableByteChannel writableByteChannel = Channels.newChannel(zipOut);
                FileChannel channel = new FileInputStream(src).getChannel();
            ) {
            zipOut.putNextEntry(new ZipEntry("1023.zip"));
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (channel.read(buffer) != -1) {
                buffer.flip();
                writableByteChannel.write(buffer);
                buffer.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("文件大小: " + src.length());
        System.out.println("耗时: " + (System.currentTimeMillis() - beginTime));
    }
}

NIO中新出了 ChannelByteBuffer。正是因为它们的结构更加符合操作系统执行I/O的方式,所以其速度相比较于传统IO而言速度有了显著的提高。Channel就像一个包含着煤矿的矿藏,而 ByteBuffer则是派送到矿藏的卡车。也就是说我们与数据的交互都是与 ByteBuffer的交互。

 

public class TestIO4 {
    public static void main(String[] args) {
        String ZIP_FILE = "1023.zip";
        File zipFile = new File(ZIP_FILE);
        File src = new File("F:\\person_code\\jvm_deep_base\\module04\\src\\main\\java\\jdk1.8.0_291.zip");
        long beginTime = System.currentTimeMillis();
        try (
                // jdk以后 这里声明的变量会自动关闭申请的资源
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
                WritableByteChannel writableByteChannel = Channels.newChannel(zipOut);
                FileChannel channel = new FileInputStream(src).getChannel();
            ) {
            zipOut.putNextEntry(new ZipEntry("1023.zip"));
            channel.transferTo(0, src.length(), writableByteChannel);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("文件大小: " + src.length());
        System.out.println("耗时: " + (System.currentTimeMillis() - beginTime));
    }
}

 使用 transferTo的效率比循环一个 Channel读取出来然后再循环写入另一个 Channel好。操作系统能够直接传输字节从文件系统缓存到目标的 Channel中,而不需要实际的 copy阶段。简单来说省去了从内核空间转到用户空间的一个过程。关于零拷贝可以参考这篇博客。地址是:https://www.cnblogs.com/ykpkris/articles/15472699.html

 

posted @ 2021-10-27 19:18  *乐途*  阅读(35)  评论(0编辑  收藏  举报