Java - 确定ZipInputStream是否包含Entry

时间:2013-08-04 14:27:04

标签: java zipfile fileinputstream

我目前正在尝试创建一个将多个ZipFile合并为一个大的方法。因此,我创建了一个获取输出文件和InputStream s。列表的方法。

这些InputStream稍后会转换为ZipInputStream s。这很好用!

但是当文件已经添加到存档时我遇到了麻烦。此时我需要覆盖已添加的条目(InputStream s具有更高的索引(列表中较低)应覆盖具有较低索引的流中的文件)。我也知道如何做到这一点:如果存档需要覆盖它,我只是不添加条目。 但问题是如何检查条目是否包含在ZipInputStream中,以便我可以跳过添加当前流的条目?

到目前为止我的代码:

    public static void makeNewZipFromInputStreamList(File outputFile,
            ArrayList<InputStream> inputStreamList,
            ArrayList<String> includeList, ArrayList<String> excludeList)
            throws IOException, IllegalArgumentException {
        final int sizeOfLists[] = new int[] { inputStreamList.size(),
                includeList.size(), excludeList.size() };

        if ((sizeOfLists[0] != sizeOfLists[1])
                || (sizeOfLists[0] != sizeOfLists[2])
                || (sizeOfLists[1] != sizeOfLists[2]))
            throw new IllegalArgumentException(
                    "The ArrayLists do not have the same size ("
                            + sizeOfLists[0] + ", " + sizeOfLists[1] + ", "
                            + sizeOfLists[2] + ")");

        final ZipOutputStream zipOutputFile = new ZipOutputStream(
                new FileOutputStream(outputFile));
        final int size = sizeOfLists[0];
        InputStream inputStreamTempArray[] = inputStreamList
                .toArray(new InputStream[size]);
        String includeArray[] = includeList.toArray(new String[size]);
        String excludeArray[] = excludeList.toArray(new String[size]);

        int i, j;
        ZipInputStream stream, streamTmp;
        ZipInputStream inputStreamArray[] = new ZipInputStream[size];
        String include, exclude, fileName;
        ZipEntry entry;

        for (i = 0; i < size; i++) {
            inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]);

            if (includeArray[i] == null) {
                includeArray[i] = "";
            }

            if (excludeArray[i] == null) {
                excludeArray[i] = "";
            }
        }

        for (i = 0; i < size; i++) {
            while ((entry = inputStreamArray[i].getNextEntry()) != null) {
                fileName = entry.getName();

                for (j = i + 1; j < size; j++) {
                    // Check if the entry exists in the following archives (Then skip this entry)
                }

                if (fileName.matches(includeArray[i]) || !fileName.matches(excludeArray[i])) {
                    zipOutputFile.putNextEntry(entry);

                    if (!entry.isDirectory()) {
                        copyStream(inputStreamArray[i], zipOutputFile, false, false);
                    }
                }
            }

            inputStreamArray[i].close();
        }

        zipOutputFile.close();
    }

copyStream:

    private static boolean copyStream(final InputStream is,
            final OutputStream os, boolean closeInputStream,
            boolean closeOutputStream) {
        try {
            final byte[] buf = new byte[1024];

            int len = 0;
            while ((len = is.read(buf)) > 0) {
                os.write(buf, 0, len);
            }

            if (closeInputStream) {
                is.close();
            }

            if (closeOutputStream) {
                os.close();
            }

            return true;
        } catch (final IOException e) {
            e.printStackTrace();
        }
        return false;
    }

修改

我有一个想法,就是从列表的末尾开始,以反过来的方式附加条目,如果已​​经输入了一个条目,它就会跳过。

当我这样做时,我得到了一个非常奇怪的错误:

java.util.zip.ZipException: invalid entry compressed size (expected 1506 but got 1507 bytes)
    at java.util.zip.ZipOutputStream.closeEntry(Unknown Source)
    at java.util.zip.ZipOutputStream.putNextEntry(Unknown Source)
    at io.brainstone.github.installer.FileUtils.makeNewZipFromInputStreamList(FileUtils.java:304)
    at io.brainstone.github.installer.Main.startInstalling(Main.java:224)
    at io.brainstone.github.installer.Window$3$1.run(Window.java:183)

这是我目前的代码:

    public static void makeNewZipFromInputStreamList(File outputFile,
            ArrayList<InputStream> inputStreamList,
            ArrayList<String> includeList, ArrayList<String> excludeList)
            throws IOException, IllegalArgumentException {
        final int sizeOfLists[] = new int[] { inputStreamList.size(),
                includeList.size(), excludeList.size() };

        if ((sizeOfLists[0] != sizeOfLists[1])
                || (sizeOfLists[0] != sizeOfLists[2])
                || (sizeOfLists[1] != sizeOfLists[2]))
            throw new IllegalArgumentException(
                    "The ArrayLists do not have the same size ("
                            + sizeOfLists[0] + ", " + sizeOfLists[1] + ", "
                            + sizeOfLists[2] + ")");

        final ZipOutputStream zipOutputFile = new ZipOutputStream(
                new FileOutputStream(outputFile));

        final int size = sizeOfLists[0];
        final InputStream inputStreamTempArray[] = inputStreamList
                .toArray(new InputStream[size]);
        final String includeArray[] = includeList.toArray(new String[size]);
        final String excludeArray[] = excludeList.toArray(new String[size]);
        final ZipInputStream inputStreamArray[] = new ZipInputStream[size];

        HashMap<String, Object[]> tmp;

        int i, j;
        String fileName;
        ZipEntry entry;

        for (i = size - 1; i >= 0; i--) {
            System.out.println(i);

            inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]);

            if (includeArray[i] == null) {
                includeArray[i] = "";
            }

            if (excludeArray[i] == null) {
                excludeArray[i] = "";
            }

            while ((entry = inputStreamArray[i].getNextEntry()) != null) {
                fileName = entry.getName();

                if (fileName.matches(includeArray[i])
                        || !fileName.matches(excludeArray[i])) {
                    // Here is where I would check if a entry is already put.
                    // Probably just by catching the exception thrown in this
                    // case
                    zipOutputFile.putNextEntry(entry);

                    if (!entry.isDirectory()) {
                        copyStream(inputStreamArray[i], zipOutputFile, false,
                                false);
                    }
                }
            }

            inputStreamArray[i].close();
        }

        zipOutputFile.close();
    }

2 个答案:

答案 0 :(得分:0)

  1. 保存从fileNameentry的地图。
  2. 迭代所有输入流中的所有条目,并将条目放入地图中,按文件名映射。最后一个条目将始终覆盖以前。完成后,每个文件名只包含所有索引最高的条目。
  3. 迭代地图的条目并将其放入zipOutputFile

    // (1) here all entries will be stored, overriding low-indexed with high-indexed
    final Map<String, ZipEntry> fileNameToZipEntry = new HashMap<String, ZipEntry>();
    
    // (2) Iterate over all entries and store in map, overriding low-indexed
    for (i = 0; i < size; i++) {
    
        while ((entry = inputStreamArray[i].getNextEntry()) != null) {
            fileName = entry.getName();
            fileNameToZipEntry.put(fileName, entry);
        }
    
        inputStreamArray[i].close();
    }
    
    // (3) Iterating the map that holds only the entries required for zipOutputFile
    int j = 0;
    for ( Set<Map.Entry<String, ZipEntry>> mapEntry : fileNameToZipEntry.entrySet() ) {
    
        if (fileName.matches(includeArray[j]) || !fileName.matches(excludeArray[j])) {
    
            zipOutputFile.putNextEntry(entry);
    
            if (!entry.isDirectory()) {
                copyStream(inputStreamArray[j], zipOutputFile, false, false);
            }
        }
        j++;
    }
    

答案 1 :(得分:0)

解决此问题的最简单方法是向后遍历ArrayLists。

    public static void makeNewZipFromInputStreamList(File outputFile,
            ArrayList<InputStream> inputStreamList,
            ArrayList<String> includeList, ArrayList<String> excludeList)
            throws IOException, IllegalArgumentException {
        final int sizeOfLists[] = new int[] { inputStreamList.size(),
                includeList.size(), excludeList.size() };

        if ((sizeOfLists[0] != sizeOfLists[1])
                || (sizeOfLists[0] != sizeOfLists[2])
                || (sizeOfLists[1] != sizeOfLists[2]))
            throw new IllegalArgumentException(
                    "The ArrayLists do not have the same size ("
                            + sizeOfLists[0] + ", " + sizeOfLists[1] + ", "
                            + sizeOfLists[2] + ")");

        final ZipOutputStream zipOutputFile = new ZipOutputStream(
                new FileOutputStream(outputFile));

        final int size = sizeOfLists[0];
        final InputStream inputStreamTempArray[] = inputStreamList
                .toArray(new InputStream[size]);
        final String includeArray[] = includeList.toArray(new String[size]);
        final String excludeArray[] = excludeList.toArray(new String[size]);
        final ZipInputStream inputStreamArray[] = new ZipInputStream[size];

        HashMap<String, Object[]> tmp;

        int i, j;
        String fileName;
        ZipEntry entry;

        for (i = size - 1; i >= 0; i--) {
            inputStreamArray[i] = new ZipInputStream(inputStreamTempArray[i]);

            if (includeArray[i] == null) {
                includeArray[i] = "";
            }

            if (excludeArray[i] == null) {
                excludeArray[i] = "";
            }

            while ((entry = inputStreamArray[i].getNextEntry()) != null) {
                fileName = entry.getName();

                if (fileName.matches(includeArray[i])
                        || !fileName.matches(excludeArray[i])) {
                    try {
                        zipOutputFile.putNextEntry(entry);

                        if (!entry.isDirectory()) {
                            copyStream(inputStreamArray[i], zipOutputFile,
                                    false, false);
                        }
                    } catch (ZipException ex) {
                        if (!ex.getMessage()
                                .matches("duplicate entry: .*\\..*")) {
                            throw new RuntimeException(
                                    "Unexpected " + ex.getClass() + " (\""
                                            + ex.getMessage()
                                            + "\")\n(only duplicate entry execptions are expected!)",
                                    ex);
                        }
                    }
                }
            }

            inputStreamArray[i].close();
        }

        zipOutputFile.close();
    }

但是谢谢你!