【问题标题】:How best to compress this folder so can be uncompressed withi Java with minimum working space如何最好地压缩此文件夹,以便可以使用 Java 以最小的工作空间解压缩
【发布时间】:2026-02-09 18:55:01
【问题描述】:

我有一个文件夹,其中包含在 linux 上创建的文件,我目前使用 gzip 进行 tar 和压缩(即 tar.gz)

然后在稍后阶段,该文件被复制到另一台 linux 机器的一个文件系统中,并使用 Java 提取到另一个文件系统中。

我的问题是压缩包为 3GB,未压缩为 5GB。两个文件系统分别是 4GB 和 6GB 我将压缩存档复制到 4GB fs,但是当我尝试将其解压缩到 6GB 时,它在未压缩时被复制到 6GB fs,因此 6GB 需要足够的空间用于压缩和它没有的未压缩格式。

我不清楚它为什么要创建这个临时文件,如果我这样做的话

cd destination folder
tar -zxvf source file

它可以在没有空间用完的情况下工作,但我需要使用纯 Java 而不是命令行来解压缩它

有没有更好的方法来压缩文件夹,因为我不受任何特定格式的限制,只要它可以用 Java 代码解压缩。我无法修改/重新配置两个文件系统的大小 - 它需要在这些边界内工作。

【问题讨论】:

  • 在传输数据时开始解压缩?我说以 300mb 的压缩数据块发送它并一次解压缩一个,你会很好地保持在两边的 1gb 余量内
  • @ug_ 更多细节请我如何分解成可以独立解压缩的块?

标签: java compression gzip tar


【解决方案1】:

仅供参考:刚刚意识到在 tar.gz 文件中,文件被 tar 压缩,然后 tar 文件被 gzip 压缩,因此在解压缩时很难避免解压缩到 tar 的中间步骤。但是,如果我手动 gzip 每个文件,然后 tar 如下:

cd foldertozip
gzip *
cd ..
tar -cvf foldertozip.tar folderzip

foldertozip.tar 的大小与原来的foldertozip.tar.gz 完全相同,但不需要中间步骤。

然后我可以:

  • 将 foldertozip.tar 复制到 4GB fs
  • 将 foldertozip.tar 解压到 6GB fs
  • 对于 foldertozip 中的每个文件 解压每个.gz

所以我们在 6GB fs 上使用的唯一额外临时空间是解压缩每个 gz 文件所需的空间。

我已经对此进行了测试,它对我有用。

【讨论】:

    【解决方案2】:

    你让我对这个很好奇,是的,这并不难。我使用 TCP 服务器和客户端只是为了完全分离输入/输出流,以确保没有恶作剧。

    本质上是在服务器上读取原始 ZIP 数据并将其发送到客户端。然后,客户端将该数据解释为ZipInputStream,并将所有条目写入输出文件夹。事实证明,您甚至不需要发送大块数据,真正分配的只是缓冲区。我分析了它发送超过 200mb 的 zip 文件,而内存消耗几乎没有发生。

    最后你确实得到了一个不错的SocketException,但这是意料之中的,因为除了必需的之外,我几乎没有添加任何错误处理。客户端关闭了连接,而服务器不喜欢这样,所以它会抛出一个错误,但是所有的数据都已经完成了,所以谁在乎呢!

    我为 ZIP 文件编写了这段代码,因为我没有注意,但我想我会发布。您可以使用一些在线库对其进行调整以使用 TAR 输入流但是代码应该给出一般的 Jist。

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Object serverWait = new Object();
        startServer(serverWait);
        synchronized (serverWait) {
            // make sure our server is started and accepting clients, otherwise we run the risk of starting the client before the server is started
            serverWait.wait(2000);
        }
        startClient();
    }
    
    private static void startServer(final Object serverWait) {
        new Thread(new Runnable() {
            @Override
            public void run() {
    
                ServerSocket serverSocket = null;
                Socket socket = null;
                InputStream is = null;
                try {
                    serverSocket = new ServerSocket(5555);
                    synchronized (serverWait) {
                        serverWait.notify();
                    }
                    socket = serverSocket.accept();
                    System.out.println("Client accepted, sending data");
                    // just send over the raw zip file and let the client sort through how to parse it
                    is = new FileInputStream("f:\\so\\zip_transfer\\ZipFile.zip");
    
                    int numRead = 0;
                    byte [] buffer = new byte[2048];
                    while((numRead = is.read(buffer)) != -1) {
                        socket.getOutputStream().write(buffer, 0, numRead);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    safeClose(socket);
                    safeClose(serverSocket);
                    safeClose(is);
                }
            }
        }).start();
    }
    
    
    private static void startClient() {
        new Thread(new Runnable() {
            @Override
            public void run() {
    
                Socket socket = null;
                ZipInputStream is = null;
                try {
                    socket = new Socket("127.0.0.1", 5555);
                    System.out.println("Client connected, retrieving data");
    
                    // the data we are receiving is in zip format
                    is = new ZipInputStream(socket.getInputStream());
                    extactZipInputStream(is, new File("f:\\so\\zip_transfer\\OutputDirectory"));
    
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    safeClose(socket);
                    safeClose(is);
                }
            }
        }).start();
    }
    
    public static void extactZipInputStream(ZipInputStream is, File outputFolder) throws ZipException, IOException  {
    
        ZipEntry entry = null;
        // Just keep going until we dont have any entries left.
        while((entry = is.getNextEntry()) != null) {
            System.out.println("Entry: " + entry.getName());
            File file = new File(outputFolder, entry.getName());
            if(entry.isDirectory()) {
                // make all the path a direcotyr
                file.mkdirs();
            } else {
                // last one isnt a directory its our file, only make our parents
                file.getParentFile().mkdirs();
    
                // write the file to the system
                FileOutputStream fos = new FileOutputStream(file);
                int numRead = 0;
                byte [] buffer = new byte[2048];
                while((numRead = is.read(buffer)) != -1) {
                    fos.write(buffer, 0, numRead);
                }
                fos.close();
            }
    
            is.closeEntry();
        }
    }
    
    private static void safeClose(Closeable closable) {
        try {
            if(closable != null) {
                closable.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    【讨论】:

    • 感谢您的努力,但不幸的是,您的回答错过了文件被 tar 化然后 gzip 压缩的关键点,因此必须在解压缩之前将其 gzip 压缩成普通的 tar。我现在有一个解决方案,我会在一分钟内发布