如何将一个巨大的zip文件拆分成多个卷?

当我通过java.util.zip.*创建zip存档时,有没有办法在多个卷中拆分生成的存档?

假设我的整个存档filesize24 MB ,我想将其拆分为3个文件,每个文件的限制为10 MB。
是否有具有此function的zip API? 或者其他任何好方法来实现这一目标?

谢谢索尔斯滕

检查: http : //saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?subb = get_topic&f = 38&t = 004618

我不知道有任何公共API可以帮助您做到这一点。 (虽然如果你不想以编程方式进行,那么像WinSplitter这样的实用程序会这样做)

我没有尝试过,但是,使用ZippedInput / OutputStream时,每个ZipEntry都有一个压缩的大小。 在创建压缩文件时,您可能会粗略估计压缩文件的大小。 如果您需要2MB的压缩文件,那么在累积条目大小为1.9MB后,您可以停止写入文件,对于清单文件和其他zip文件特定元素占用.1MB。 因此,简而言之,您可以在ZippedInputStream上编写一个包装器,如下所示:

 import java.util.zip.ZipOutputStream; import java.util.zip.ZipEntry; import java.io.FileOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; public class ChunkedZippedOutputStream { private ZipOutputStream zipOutputStream; private String path; private String name; private long currentSize; private int currentChunkIndex; private final long MAX_FILE_SIZE = 16000000; // Whatever size you want private final String PART_POSTFIX = ".part."; private final String FILE_EXTENSION = ".zip"; public ChunkedZippedOutputStream(String path, String name) throws FileNotFoundException { this.path = path; this.name = name; constructNewStream(); } public void addEntry(ZipEntry entry) throws IOException { long entrySize = entry.getCompressedSize(); if((currentSize + entrySize) > MAX_FILE_SIZE) { closeStream(); constructNewStream(); } else { currentSize += entrySize; zipOutputStream.putNextEntry(entry); } } private void closeStream() throws IOException { zipOutputStream.close(); } private void constructNewStream() throws FileNotFoundException { zipOutputStream = new ZipOutputStream(new FileOutputStream(new File(path, constructCurrentPartName()))); currentChunkIndex++; currentSize = 0; } private String constructCurrentPartName() { // This will give names is the form of .part.0.zip, .part.1.zip, etc. StringBuilder partNameBuilder = new StringBuilder(name); partNameBuilder.append(PART_POSTFIX); partNameBuilder.append(currentChunkIndex); partNameBuilder.append(FILE_EXTENSION); return partNameBuilder.toString(); } } 

上述程序只是一种方法的暗示,而不是任何方式的最终解决方案

如果目标是让输出与pkzip和winzip兼容,我不知道有任何开源库可以做到这一点。 我们对其中一个应用程序有类似的要求,最后我编写了自己的实现(与zip标准兼容)。 如果我记得,对我们来说最困难的事情是我们必须动态生成单个文件(大多数zip实用程序的工作方式是创建大型zip文件,然后返回并稍后拆分 – 这样更容易实现。花了大约一天写,2天调试。

zip标准解释了文件格式的外观。 如果你不怕卷起袖子,这绝对可行。 您必须自己实现一个zip文件生成器,但您可以使用Java的Deflator类生成压缩数据的段流。 你必须自己生成文件和节头,但它们只是字节 – 一旦你潜入就没什么难的。

这是zip规范 – 部分K具有您正在寻找的信息,但您还需要阅读A,B,C和F. 如果你正在处理非常大的文件(我们是),你也必须进入Zip64的东西 – 但对于24 MB,你没事​​。

如果你想潜入并尝试它 – 如果你遇到问题,回发后我会看看我是否可以提供一些指示。

下面的代码是我的解决方案,根据所需的大小将目录结构中的zip文件拆分为块。 我发现以前的答案很有用,所以希望用类似但更简洁的方法做出贡献。 这段代码适合我的特定需求,我相信还有改进的余地。

 private final static long MAX_FILE_SIZE = 1000 * 1000 * 1024; // around 1GB private final static String zipCopyDest = "C:\\zip2split\\copy"; public static void splitZip(String zipFileName, String zippedPath, String coreId) throws IOException{ System.out.println("process whole zip file.."); FileInputStream fis = new FileInputStream(zippedPath); ZipInputStream zipInputStream = new ZipInputStream(fis); ZipEntry entry = null; int currentChunkIndex = 0; //using just to get the uncompressed size of the zipentries long entrySize = 0; ZipFile zipFile = new ZipFile(zippedPath); Enumeration enumeration = zipFile.entries(); String copDest = zipCopyDest + "\\" + coreId + "_" + currentChunkIndex +".zip"; FileOutputStream fos = new FileOutputStream(new File(copDest)); BufferedOutputStream bos = new BufferedOutputStream(fos); ZipOutputStream zos = new ZipOutputStream(bos); long currentSize = 0; try { while ((entry = zipInputStream.getNextEntry()) != null && enumeration.hasMoreElements()) { ZipEntry zipEntry = (ZipEntry) enumeration.nextElement(); System.out.println(zipEntry.getName()); System.out.println(zipEntry.getSize()); entrySize = zipEntry.getSize(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); //long entrySize = entry.getCompressedSize(); //entrySize = entry.getSize(); //gives -1 if((currentSize + entrySize) > MAX_FILE_SIZE) { zos.close(); //construct a new stream //zos = new ZipOutputStream(new FileOutputStream(new File(zippedPath, constructCurrentPartName(coreId)))); currentChunkIndex++; zos = getOutputStream(currentChunkIndex, coreId); currentSize = 0; }else{ currentSize += entrySize; zos.putNextEntry(new ZipEntry(entry.getName())); byte[] buffer = new byte[8192]; int length = 0; while ((length = zipInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } byte[] unzippedFile = outputStream.toByteArray(); zos.write(unzippedFile); unzippedFile = null; outputStream.close(); zos.closeEntry(); } //zos.close(); } } finally { zos.close(); } } public static ZipOutputStream getOutputStream(int i, String coreId) throws IOException { System.out.println("inside of getOutputStream().."); ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipCopyDest + "\\" + coreId + "_" + i +".zip")); // out.setLevel(Deflater.DEFAULT_COMPRESSION); return out; } public static void main(String args[]) throws IOException{ String zipFileName = "Large_files _for_testing.zip"; String zippedPath= "C:\\zip2split\\Large_files _for_testing.zip"; String coreId = "Large_files _for_testing"; splitZip(zipFileName, zippedPath, coreId); }