如何最好地压缩此文件夹,以便可以使用 Java 以最小的工作空间解压缩

Posted

技术标签:

【中文标题】如何最好地压缩此文件夹,以便可以使用 Java 以最小的工作空间解压缩【英文标题】:How best to compress this folder so can be uncompressed withi Java with minimum working space 【发布时间】:2014-06-30 21:27:48 【问题描述】:

我有一个文件夹,其中包含在 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_ 更多细节请我如何分解成可以独立解压缩的块? 【参考方案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。我现在有一个解决方案,我会在一分钟内发布

以上是关于如何最好地压缩此文件夹,以便可以使用 Java 以最小的工作空间解压缩的主要内容,如果未能解决你的问题,请参考以下文章

如何最好地存储kd树中的行

pyspark如何加载压缩的snappy文件

如何使用java压缩文件夹本身

Java实现打包压缩文件或文件夹生成zip以实现多文件批量下载

与查看结果相比,如何最好地检查已导出到xlsx文件的nvarchar字段的完整性?

是否的逻辑值如何表示?图片,视频,文件如何储存如何表示