代码之家  ›  专栏  ›  技术社区  ›  phoenixSid

在apache Camel中,无需将整个文件加载到内存中即可对大型文件进行压缩和解压缩

  •  3
  • phoenixSid  · 技术社区  · 6 年前

    我们使用Apache Camel来压缩和解压缩文件。 我们使用标准 .marshal().gzip() .unmarshall().gzip() API。

    我们的问题是,当我们得到非常大的文件时,比如800MB到1GB以上的文件大小,我们的应用程序就会耗尽内存,因为整个文件都会加载到内存中进行压缩和解压缩。

    是否有任何camel api或java库可以帮助压缩/解压文件,而无需将整个文件加载到内存中。

    还有一个类似的未解之谜 here

    1 回复  |  直到 6 年前
        1
  •  3
  •   Zabuzard Louis-Philippe Lebouthillier    6 年前

    解释

    使用不同的方法: 流动 文件。

    也就是说,不要将其完全加载到内存中,而是逐字节读取它,同时逐字节写回它。

    获取 InputStream 到文件中,包装一些 GZipInputStream 围绕读取每个字节的字节,写入 OutputStream

    如果要压缩存档,则相反。然后你把 输出流 一些人 GZipOutputStream


    密码

    示例使用 Apache Commons Compress 但所有库的代码逻辑都保持不变。

    打开包装a gz 存档:

    Path inputPath = Paths.get("archive.tar.gz");
    Path outputPath = Paths.get("archive.tar");
    
    try (InputStream fin = Files.newInputStream(inputPath );
            OutputStream out = Files.newOutputStream(outputPath);) {
        GZipCompressorInputStream in = new GZipCompressorInputStream(
            new BufferedInputStream(fin));
    
        // Read and write byte by byte
        final byte[] buffer = new byte[buffersize];
        int n = 0;
        while (-1 != (n = in.read(buffer))) {
            out.write(buffer, 0, n);
        }
    }
    

    包装组件 广州 存档:

    Path inputPath = Paths.get("archive.tar");
    Path outputPath = Paths.get("archive.tar.gz");
    
    try (InputStream in = Files.newInputStream(inputPath);
            OutputStream fout = Files.newOutputStream(outputPath);) {
        GZipCompressorOutputStream out = new GZipCompressorOutputStream(
            new BufferedOutputStream(fout));
    
        // Read and write byte by byte
        final byte[] buffer = new byte[buffersize];
        int n = 0;
        while (-1 != (n = in.read(buffer))) {
            out.write(buffer, 0, n);
        }
    }
    

    您也可以包装 BufferedReader PrintWriter 如果你觉得和他们在一起更舒服的话。它们自己管理缓冲区,您可以读写 line s而不是 byte s、 请注意,只有当您读取的文件中包含行而不是其他格式时,这才是正确的。