簡體   English   中英

如何在 Java 中創建未壓縮的 Zip 存檔

[英]How to create Uncompressed Zip archive in Java

我正在使用 Java 的 Zip 實用程序 package,想知道如何創建完全沒有壓縮的 zip 文件。 將級別設置為 0 沒有幫助。 這是正確的嗎?

此外,當我使用STORED方法時,它會拋出以下異常:

java.util.zip.ZipException: STORED entry missing size, compressed size, or crc-32

我可以設置大小但現在拋出以下異常:

java.util.zip.ZipException: invalid entry crc-32 

我只是通過搜索 web 來關注所有可用的示例,我想我無法真正正確地理解它。 如果有人可以幫助我並向我提供建議以糾正我可能正在做的問題,那就太好了。

我對aperkins解決方案很感興趣 (自刪除以來),但我知道它為何有效。 這條線(后來在他的回答中得到糾正)

zipOut.setLevel(ZipOutputStream.STORED); // accidentally right

使用靜態值ZipOutputStream.STORED ,巧合等於0 那么該行正在做的是將默認DEFLATED方法使用的級別設置為零壓縮(這顯然是您想要做的,但碰巧只能靠運氣工作)。 因此,要明確安全地獲得您想要的內容,請使用以下內容:

zipOut.setMethod(ZipOutputStream.DEFLATED); // this line optional
zipOut.setLevel(0);

要么

zipOut.setLevel(Deflater.NO_COMPRESSION);

如果你使用

zipOut.setMethod(ZipOutputStream.STORED);
zipOut.setLevel(Deflater.NO_COMPRESSION);

你可能會得到Keya在原始問題中提到的異常。 我相信Christian Schlichtherle是對的; 您正在獲取例外,因為您沒有在條目中設置CRC。 這種影響是要使用STORED方法,你必須首先讀取整個條目文件,或者在調用zipOut.putNextEntry()之前找到一些其他方法來設置大小,壓縮大小(必須相等)和CRC 。 否則,如果通過向輸出流寫入太多字節來超出size屬性,則會遇到更多異常。 似乎ZIP規范說如果你正在編寫STORED數據,那么它必須在數據本身之前編寫標題[包括CRC-32和長度]“,因此需要在它之前設置java API可以啟動,因為它基本上只支持流式傳輸到最終的zip文件。

您需要使用STORED方法,但這需要您所設置的sizecompressedSizecrc32相應的屬性ZipEntry后,才能調用putNextEntryZipOutputStream 您可以使用Crc32OutputStream預先計算CRC-32。

供參考:

在JDK方法的源代碼[java.util.zip.ZipOutputStream.setLevel(int)]中:

public void setLevel(int level) {
    def.setLevel(level);
}

它只是將壓縮級別設置重定向到字段變量[def],這是[java.util.zip.Deflater]的一個實例。

並在類[java.util.zip.Deflater]的源代碼中:

/**
 * Compression level for no compression.
 */
public static final int NO_COMPRESSION = 0;

/**
 * Compression level for fastest compression.
 */
public static final int BEST_SPEED = 1;

/**
 * Compression level for best compression.
 */
public static final int BEST_COMPRESSION = 9;

/**
 * Default compression level.
 */
public static final int DEFAULT_COMPRESSION = -1;

所以,如果你使用常量值[Deflater.NO_COMPRESSION],我認為它會更具可讀性:

zipOut.setMethod(ZipOutputStream.DEFLATED);
zipOut.setLevel(Deflater.NO_COMPRESSION);
    public static void zipForStored(String srcFile, String zipFile) throws Exception {
        File file = new File(zipFile);
        if (!file.exists()) file.createNewFile();
        ZipOutputStream outZip = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
        outZip.setMethod(ZipOutputStream.STORED);
        ZipFiles(srcFile, null, "", outZip);
        outZip.finish();
        outZip.close();
    }

    private static void ZipFiles(String folder, FilenameFilter filter, String file, ZipOutputStream zipOutputSteam) throws Exception {
        if (zipOutputSteam == null)
            return;
        File f = new File(folder, file);
        if (f.isFile()) {
            ZipEntry zipEntry = new ZipEntry(file);
            FileInputStream inputStream = new FileInputStream(f);
            zipEntry.setSize(f.length());
            zipEntry.setCompressedSize(f.length());
            zipEntry.setCrc(computeCrc(f));
            zipOutputSteam.putNextEntry(zipEntry);
            int len;
            byte[] buffer = new byte[4096];
            while ((len = inputStream.read(buffer)) != -1) {
                zipOutputSteam.write(buffer, 0, len);
            }
            zipOutputSteam.closeEntry();
            inputStream.close();
        } else {
            String fileList[] = f.list(filter);
            if (fileList.length <= 0) {
                ZipEntry zipEntry = new ZipEntry(file + File.separator);
                zipEntry.setSize(0);
                zipEntry.setCompressedSize(0);
                zipEntry.setCrc(0);
                zipOutputSteam.putNextEntry(zipEntry);
                zipOutputSteam.closeEntry();
            }
            for (int i = 0; i < fileList.length; i++) {
                if (TextUtils.isEmpty(file)) {
                    ZipFiles(folder, filter, fileList[i], zipOutputSteam);
                } else {
                    ZipFiles(folder, filter, file + File.separator + fileList[i], zipOutputSteam);
                }
            }
        }
    }

    /**
     * Computes the CRC checksum for the given file.
     *
     * @param file The file to compute checksum for.
     * @return A CRC32 checksum.
     * @throws IOException If an I/O error occurs.
     */
    private static long computeCrc(File file) throws IOException {
        CRC32 crc = new CRC32();
        InputStream in = new FileInputStream(file);

        try {
            byte[] buf = new byte[8192];
            int n = in.read(buf);
            while (n != -1) {
                crc.update(buf, 0, n);
                n = in.read(buf);
            }
        } finally {
            in.close();
        }
        return crc.getValue();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM