3

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

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

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

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

我愿意提供建议或更好的工作示例。

4

3 回答 3

7

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);

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

于 2014-09-16T23:22:09.957 回答
2

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

  • 未压缩文件数:116
  • 总大小(未压缩):29.1 GB
  • ZIP 文件大小限制(每个):3 GB [MAX_ZIP_SIZE]
  • 总大小(压缩):7.85 GB
  • ZIP 文件数(拆分为MAX_ZIP_SIZE):3

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

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

package com.company;

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 QdeZip {

    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";
    }
}

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

于 2017-11-06T11:01:29.397 回答
0

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.

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.

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 :-)

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

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;
    }
}   
于 2012-06-20T12:38:17.200 回答