简体   繁体   English

Java-确定ZipInputStream是否包含条目

[英]Java - Determine if a ZipInputStream contains a Entry

I'm currently trying to create a method that merges several ZipFile s into one big. 我目前正在尝试创建一种将多个ZipFile合并为一个大的方法。 Therefore I created a method that takes a output file and a list of InputStream s. 因此,我创建了一个采用输出文件和InputStream列表的方法。

These InputStream s are later transformed into ZipInputStream s. 这些InputStream稍后将转换为ZipInputStream That works fine! 很好!

But I have trouble when a file has already been added to the archive. 但是当文件已经添加到存档中时,我遇到了麻烦。 At this point I need to override the entry already added ( InputStream s with a higher index (lower in the list) should override the files from streams with a lower index). 在这一点上,我需要覆盖已经添加的条目(具有较高索引(列表中较低)的InputStream应当覆盖具有较低索引的流中的文件)。 I also know how to do that: I just do not add the entry if a archive that would need to override it. 我也知道该怎么做:如果需要覆盖它,我只是不添加该条目。 But the problem is how could I check if a entry is contained in a ZipInputStream so I can skip the addition of the entry for the current stream? 但是问题是如何检查ZipInputStream是否包含条目,以便可以跳过当前流的条目添加?

My code so far: 到目前为止,我的代码:

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

EDIT: 编辑:

I had the idea to just append the entries the other way round meaning starting from the end of the list and if a entry is already put it is just going to skip. 我有一个想法,就是以相反的方式附加条目,即从列表的末尾开始,如果条目已经放置,则将跳过该条目。

When I'm doing this I get a really weird error: 当我这样做时,我会收到一个非常奇怪的错误:

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)

This is my current code: 这是我当前的代码:

    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();
    }
  1. Hold a map from fileName to entry . 保持从fileNameentry的映射。
  2. Iterate over all entries in all input streams and put the entries in the map, mapped by file name. 遍历所有输入流中的所有条目,然后将条目放入按文件名映射的映射中。 Last entry will always override previous. 最后一个条目将始终覆盖上一个条目。 When you finish you have only all highest-indexed entries per file name. 完成后,每个文件名只有所有索引最高的条目。
  3. Iterate over the map's entries and put them to zipOutputFile . 遍历地图的条目,并将其放入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++; } 

The simplest way to solve this is iterating backwards through the ArrayLists. 解决此问题的最简单方法是向后遍历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();
    }

But thank you anyways! 但是还是谢谢你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM