如何在Java中创建一个ZIP文件内包含另一个ZIP文件?

3
我正在尝试在ZIP文件中创建一个ZIP文件,以重构我在Java中获得的以前的内存zip结构。但是我失败了,因为在初始ZIP文件中创建的内部ZIP上出现了错误。该文件已损坏。当我尝试打开它时,会出现“意外的文件结尾”错误。
我有以下结构:
-input.zip --innerInput.zip 代码将所有内容解压到内存中使用java堆栈和映射。然后它创建input2.zip,并将innerInput.zip放入其中。
总结一下:我需要在内存中创建一个包含ZIP文件的ZIP文件(不要暂时保存在磁盘上)。
代码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.lang3.StringUtils;

public class ZipHandler1 {

    private static final int BUFFER_SIZE = 2048;

    private static final String ZIP_EXTENSION = ".zip";
    public static final Integer FOLDER = 1;
    public static final Integer ZIP = 2;
    public static final Integer FILE = 3;


    public static Deque<Map<Integer, Object[]>> unzip(ByteArrayOutputStream zippedOutputFile) {

        try {

            ZipInputStream inputStream = new ZipInputStream(
          new BufferedInputStream(new ByteArrayInputStream(
              zippedOutputFile.toByteArray())));

            ZipEntry entry;

            Deque<Map<Integer, Object[]>> result = new ArrayDeque<Map<Integer, Object[]>>();

            while ((entry = inputStream.getNextEntry()) != null) {

                LinkedHashMap<Integer, Object[]> map = new LinkedHashMap<Integer, Object[]>();
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                System.out.println("\tExtracting entry: " + entry);
                int count;
                byte[] data = new byte[BUFFER_SIZE];
                if (!entry.isDirectory()) {
                    BufferedOutputStream out = new BufferedOutputStream(
          outputStream, BUFFER_SIZE);

                while ((count = inputStream.read(data, 0, BUFFER_SIZE)) != -1) {
                    out.write(data, 0, count);
                }

                out.flush();
                out.close();

                //  recursively unzip files
                if (entry.getName().toUpperCase().endsWith(ZIP_EXTENSION.toUpperCase())) {
                map.put(ZIP, new Object[] {entry.getName(), unzip(outputStream)});
                result.add(map);

                } else { 
                    map.put(FILE, new Object[] {entry.getName(), outputStream});
                    result.add(map);
                }
                } else {
                    map.put(FOLDER, new Object[] {entry.getName(), 
                    unzip(outputStream)});
                    result.add(map);
                }
            }

        inputStream.close();

        return result;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

package course.hernan;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.IOUtils;

public class FileReader {

  private static final int  BUFFER_SIZE = 2048;

  public static void main(String[] args) {

    try {
      File f = new File("DIR/inputs.zip");
      FileInputStream fis = new FileInputStream(f);
      BufferedInputStream bis = new BufferedInputStream(fis);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      BufferedOutputStream bos = new BufferedOutputStream(baos);
      byte[] buffer = new byte[BUFFER_SIZE];

      while (bis.read(buffer, 0, BUFFER_SIZE) != -1) {
        bos.write(buffer);
      }

      bos.flush();
      bos.close();
      bis.close();

      Deque<Map<Integer, Object[]>> outputDataStack = ZipHandler1.unzip(baos);

      //Output file
      File fout = new File("DIR/inputs2.zip");

      ZipOutputStream zipOutput = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(fout)));

      processZip(outputDataStack, zipOutput);
      zipOutput.close();

    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
}

private static final void processZip(Deque<Map<Integer, Object[]>> outputDataStack, 
  ZipOutputStream zipOutput) throws IOException {

while (!outputDataStack.isEmpty()) {
    Map<Integer, Object[]> map = outputDataStack.pop();

    for (Map.Entry<Integer, Object[]> entry : map.entrySet()) {
        System.out.println("KEY:" + entry.getKey());
        Object[] values = entry.getValue();
        String entryName = (String)values[0];

        if (entry.getKey().equals(ZipHandler1.FILE)) {
            System.out.println("..........................");
            System.out.println("type: FILE");
            System.out.println("Name: " + entryName);

            zipOutput.putNextEntry(new ZipEntry(entryName));
            byte[] outputByteArray = ((ByteArrayOutputStream)values[1]).toByteArray();

            IOUtils.write(outputByteArray, zipOutput);
            zipOutput.closeEntry();
            ((ByteArrayOutputStream)values[1]).close();

        } else if (entry.getKey().equals(ZipHandler1.FOLDER)) {
            System.out.println("..........................");
            System.out.println("type: FOLDER");
            System.out.println("Name: " + entryName);

            zipOutput.putNextEntry(new ZipEntry(entryName));
            System.out.println("..........................");
            zipOutput.closeEntry();

        } else if (entry.getKey().equals(ZipHandler1.ZIP)) {
            System.out.println("..........................");
            System.out.println("type: ZIP");
            System.out.println("Name: " + entryName);

            zipOutput.putNextEntry(new ZipEntry(entryName));

            ByteArrayOutputStream innerZipByteArray = new ByteArrayOutputStream(BUFFER_SIZE);
            ZipOutputStream innerZipOutput = new ZipOutputStream(
          new BufferedOutputStream(innerZipByteArray));

            processZip((Deque<Map<Integer,Object[]>>)values[1], innerZipOutput);
            innerZipOutput.flush();
            IOUtils.write(zzzz.toByteArray(), zipOutput);
            innerZipOutput.close();
            zipOutput.closeEntry();
            System.out.println("..........................");
        }
            System.out.println("..........................");
            zipOutput.closeEntry();
        }
    }
}

有人吗?如果需要,我很乐意添加更多信息。 - R TheWriter
所以问题是在内存中解压包含嵌套zip文件的zip文件,我知道这很困难...有人能帮忙吗? - R TheWriter
1个回答

4

感谢我!

这个答案对我来说很难找到,可能对别人来说很明显。

简短的回答:我关闭了内部ZIP流太快了。

好的,问题是将一个ZIP存储在另一个ZIP中,对吧? 那么,我之所以会出现错误,是因为内部zip关闭得太快了。

解决方案:

像这样创建内部zip文件: ByteArrayOutputStream innerZipBufferOutput = new ByteArrayOutputStream(BUFFER_SIZE); ZipOutputStream innerZipOutput = new ZipOutputStream( new BufferedOutputStream(innerZipBufferOutput));

将字节(信息)写入内部zip

关闭内部zip流 innerZipOutput.close(); **我关闭的时机不对*

此时,以字节形式的数据位于innerZipBufferOutput中。

设置外部zip文件中内部zip文件的条目

ZipEntry newEntry = new ZipEntry(entryName);
zipOutput.putNextEntry(newEntry);  

将内部的zip文件写入外部的zip文件中。
zipOutput.write(innerZipBufferOutputByteArray);

关闭外侧拉链。
zipOutput.flush();
zipOutput.closeEntry();

看这里!

示例(代码片段) -- 你有一个ZipOutputStream(外部zip文件)

ByteArrayOutputStream innerZipBufferOutput = new ByteArrayOutputStream(BUFFER_SIZE);
ZipOutputStream innerZipOutput = new ZipOutputStream(new BufferedOutputStream(innerZipBufferOutput)); 

<<process - e.g. create your inner zip file>>

innerZipOutput.flush();
innerZipOutput.close();

ZipEntry newEntry = new ZipEntry(<<your entry name>>); 

zipOutput.setMethod(ZipOutputStream.STORED);

byte[] innerZipBufferOutputByteArray = innerZipBufferOutput.toByteArray();

//Create the nested ZIP inside the outer ZIP 
ZipEntry newEntry = new ZipEntry(entryName); 
zipOutput.putNextEntry(newEntry);

zipOutput.write(innerZipBufferOutputByteArray);


zipOutput.closeEntry();
zipOutput.close();

我正在尝试创建相同的内容,但遇到了问题。当我解压缩时,它会显示文件意外结束的错误。 - user2702700
内部的innerZipBufferOutput流是为固定的BUFFER_SIZE创建的。这意味着写入到此(ByteArrayOutputStream)的数据应超过BUFFER_SIZE。对吧?此外,我感觉缺少一个循环来写入此流,然后读取它。 - Abhishek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接