0

我目前正在尝试创建一种将几个ZipFiles 合并为一个大的方法。因此,我创建了一个采用输出文件和InputStreams 列表的方法。

这些InputStreams 稍后被转换为ZipInputStreams。这很好用!

但是当文件已经添加到存档中时,我遇到了麻烦。此时我需要覆盖已添加的条目(InputStream具有较高索引(列表中较低)的 s 应该覆盖具有较低索引的流中的文件)。我也知道怎么做:如果存档需要覆盖它,我只是不添加条目。但问题是如何检查条目是否包含在 a 中,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();
    }

复制流:

    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();
    }
4

2 回答 2

0

解决这个问题的最简单方法是向后遍历 ArrayList。

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

不过还是谢谢你!

于 2013-08-06T17:01:29.143 回答
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++;
    }
    
于 2013-08-04T14:56:49.490 回答