如何创建具有最大文件大小限制的 java zip 档案

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11104889/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 03:48:34  来源:igfitidea点击:

how to create java zip archives with a max file size limit

javazip

提问by androidu

I need to write an algorithm in java (for an android app) to read a folder containing more folders and each of those containing images and audio files so the structure is this: mainDir/categorySubfolder/myFile1.jpg

我需要在java中编写一个算法(对于一个android应用程序)来读取一个包含更多文件夹的文件夹,每个文件夹都包含图像和音频文件,所以结构是这样的: mainDir/categorySubfolder/myFile1.jpg

My problem is that I need to limit the size of the archive to 16mb and at runtime, create as many archives as needed to contain all my files from my main mainDirfolder.

我的问题是我需要将档案的大小限制为 16mb,并在运行时根据需要创建尽可能多的档案以包含我的主mainDir文件夹中的所有文件。

I tried several examples from the net and I read the java documentation but I can't manage to understand and put it all together the way I need it. Has someone done this before or has a link or an example for me?

我从网上尝试了几个例子,我阅读了 java 文档,但我无法理解并按照我需要的方式将它们组合在一起。有没有人以前做过这个或者有链接或例子给我?

I resolved the reading of the files with a recursive method but I can't write the logic for the zip creation.

我用递归方法解决了文件的读取问题,但我无法编写 zip 创建的逻辑。

I'm open for suggestions or better a working example.

我愿意接受建议或更好的工作示例。

回答by Arash

zip4jis a great library that can create multi-part zip files.

zip4j是一个很棒的库,可以创建多部分 zip 文件。

net.lingala.zip4j.core.ZipFile zipFile = new ZipFile("out.zip");
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
zipFile.createZipFileFromFolder("path/to/source/dir", parameters, true, maximum size);

You can find more examples on their web-site.

您可以在他们的网站上找到更多示例。

回答by Azam

I am using below code/class to split and zip a large amount/size of files. I have tested this class on below

我正在使用以下代码/类来拆分和压缩大量/大小的文件。我已经在下面测试了这门课

  • number of uncompressed files : 116
  • total size (uncompressed) : 29.1 GB
  • ZIP file size limit (each) : 3 GB[MAX_ZIP_SIZE]
  • total size (compressed) : 7.85 GB
  • number of ZIP file (splited as MAX_ZIP_SIZE): 3
  • 未压缩文件数:116
  • 总大小(未压缩):29.1 GB
  • ZIP 文件大小限制(每个):3 GB[MAX_ZIP_SIZE]
  • 总大小(压缩):7.85 GB
  • ZIP 文件的数量(拆分为MAX_ZIP_SIZE):3

you have to change the value of MAX_ZIP_SIZEto 16(MB)*1024*1024=16777216-22(zip header size)=16777194.
In my code, MAX_ZIP_SIZE set to 3 GB (ZIP has limitation of 4GB on various things).

您必须将MAX_ZIP_SIZE的值更改为 16(MB)*1024*1024=16777216-22(zip header size)= 16777194
在我的代码中,MAX_ZIP_SIZE 设置为 3 GB(ZIP 在各种情况下限制为 4GB)。

final long MAX_ZIP_SIZE = 3221225472L; //3 GB

最后长 MAX_ZIP_SIZE = 3221225472L;//3 GB

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class QDE_ZIP {

    public static String createZIP(String directoryPath, String zipFileName, String filesToZip) {
        try {
            final int BUFFER = 104857600; // 100MB
            final long MAX_ZIP_SIZE = 3221225472L; //3 GB
            long currentSize = 0;
            int zipSplitCount =0;
            String files[] = filesToZip.split(",");
            if (!directoryPath.endsWith("/")) {
                directoryPath = directoryPath + "/";
            }
            byte fileRAW[] = new byte[BUFFER];
            ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(directoryPath + zipFileName.toUpperCase()));
            ZipEntry zipEntry;
            FileInputStream entryFile;
            for (String aFile : files) {
                zipEntry = new ZipEntry(aFile);
                if (currentSize >= MAX_ZIP_SIZE)
                {
                    zipSplitCount ++;
                    //zipOut.closeEntry();
                    zipOut.close();
                    zipOut = new ZipOutputStream(new FileOutputStream(directoryPath + zipFileName.toLowerCase().replace(".zip", "_"+zipSplitCount+".zip").toUpperCase()));
                    currentSize = 0;
                }
                zipOut.putNextEntry(zipEntry);
                entryFile = new FileInputStream(directoryPath + aFile);

                int count;
                while ((count = entryFile.read(fileRAW, 0, BUFFER)) != -1) {
                    zipOut.write(fileRAW, 0, count);

                    //System.out.println("number of Bytes read = " + count);
                }
                entryFile.close();
                zipOut.closeEntry();
                currentSize += zipEntry.getCompressedSize();
            }

            zipOut.close();
            //System.out.println(directory + " -" + zipFileName + " -Number of Files = " + files.length);
        } catch (FileNotFoundException e) {
            return "FileNotFoundException = " + e.getMessage();
        } catch (IOException e) {
            return "IOException = " + e.getMessage();
        } catch (Exception e) {
            return "Exception = " + e.getMessage();
        }

        return "1";
    }

}

I have returned all Exception Messagesas String to work with it. this my own case related to project.

我已将所有异常消息作为字符串返回以使用它。这是我自己的与项目相关的案例。

回答by matt freake

As far as I can see How to split a huge zip file into multiple volumes?just suggests keeping track of the archive size so far, and when it approaches some arbitrary value (which should be lower than your max), it'll decide to start a new file. So for a 16MB limit, you could set the value to 10MB and start a new zip whenever this is reached, but if you reach 9MB and your next file zips down to 8MB, you'll end up with a zip bigger than your limit.

据我所知如何将巨大的 zip 文件拆分为多个卷?只是建议到目前为止跟踪存档大小,当它接近某个任意值(应该低于您的最大值)时,它会决定开始一个新文件。因此,对于 16MB 的限制,您可以将该值设置为 10MB 并在达到此值时启动一个新的 zip,但是如果您达到 9MB 并且您的下一个文件压缩到 8MB,您最终会得到一个大于您的限制的 zip。

The code given in that post didn't seem to work for me because 1) it got the size before the ZipEntry was created, so it was always 0 and 2) it didn't write out any zip :-) If I've got that wrong - let me know.

那篇文章中给出的代码似乎对我不起作用,因为 1)它在创建 ZipEntry 之前获得了大小,所以它总是 0 和 2)它没有写出任何 zip :-) 如果我已经弄错了 - 让我知道。

The following works for me. For simplicity, I've taken it out of the Wrapper and just have it all in main(String args[]). There are many, many ways this code could be improved :-)

以下对我有用。为简单起见,我已将其从 Wrapper 中取出,并将其全部放在 main(String args[]) 中。有很多很多方法可以改进这段代码:-)

import java.util.zip.*;  
import java.io.*;   



    public class ChunkedZipTwo {

        static final long MAX_LIMIT=10 * 1000 * 1024; //10MB limit - hopefully this 


        public static void main(String[] args)  throws Exception {      


            String[] files = {"file1", "file2", "file3"};
            int i = 0;
            boolean needNewFile = false;
            long overallSize = 0;
            ZipOutputStream out = getOutputStream(i);
            byte[] buffer = new byte[1024];

            for (String thisFileName: files) {


                    if (overallSize > MAX_LIMIT) {
                        out.close();
                        i++;
                        out = getOutputStream(i);
                        overallSize=0;
                    }

                    FileInputStream in = new FileInputStream(thisFileName);
                    ZipEntry ze = new ZipEntry(thisFileName);
                    out.putNextEntry(ze);   
                    int len;   
                    while ((len = in.read(buffer)) > 0) {   
                        out.write(buffer, 0, len);   
                    }   
                    out.closeEntry();
                    in.close(); 
                    overallSize+=ze.getCompressedSize();




            }
            out.close();    
        }

        public static ZipOutputStream getOutputStream(int i) throws IOException {
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream("bigfile" + i +".zip"));   
            out.setLevel(Deflater.DEFAULT_COMPRESSION);
            return out;
        }
}