【问题标题】:How can I make my Java-generated zip file identical to a WinZip-generated one如何使我的 Java 生成的 zip 文件与 WinZip 生成的文件相同
【发布时间】:2014-11-04 19:51:54
【问题描述】:

我有一个将目录内容压缩到 zip 文件中的类。我正在使用的代码如下。我遇到的问题是我生成的 zip 文件无法被我正在加载的应用程序读取。但是,如果我解压缩正在生成的 zip 文件并使用 WinZip 将其重新压缩备份,则可以使用该文件。我无法控制加载 zip 的目标应用程序,所以我所能做的就是让我的文件看起来像 WinZip 生成的版本。我使用 WinZip 详细诊断功能打开了每个 zip 文件,我可以看到生成的文件有很多差异,但我不明白哪些文件可能导致问题。有关示例,请参见问题的底部。

package com.mycompany.utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;

public class FileZipper {

    private static final Logger LOGGER = Logger.getLogger(FileZipper.class);
    private String destinationZipFile;
    private String sourceDirectory;

    List<String> fileList;
    private File zipFile;

    public File getZipFile() {
        return zipFile;
    }

    /**
     * Zips a source directory into the destination zip file
     * 
     * @param source
     * @param destination
     */
    FileZipper(String source, String destination) {
        LOGGER.info("Zipping source directory: "+source);
        LOGGER.info("To destination zip file:  "+destination);
        this.destinationZipFile = destination;
        this.sourceDirectory = source;
        fileList = new ArrayList<String>();
        generateFileList(new File(sourceDirectory));
        compressDirectoryContentsToZip(sourceDirectory, destinationZipFile);
    }

    /**
     * Traverse a directory and get all files, and add the file into fileList
     * 
     * @param node
     *            file or directory
     */
    public void generateFileList(File node) {

        // add file only
        if (node.isFile()) {
            fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
        }

        if (node.isDirectory()) {
            if(node.toString() != sourceDirectory) {
                fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
            }
            String[] subNodes = node.list();
            for (String filename : subNodes) {
                generateFileList(new File(node, filename));
            }
        }

    }

    /**
     * Compress a directory to a zip file
     * @param sourceDirectory
     * @param destinationZipFile
     */
    public void compressDirectoryContentsToZip(String sourceDirectory,
        String destinationZipFile) {

        this.zipFile = new File(destinationZipFile);

        byte[] buffer = new byte[4096];

        try {

            FileOutputStream fos = new FileOutputStream(destinationZipFile);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            ZipOutputStream zos = new ZipOutputStream(bos);
            zos.setMethod(ZipOutputStream.DEFLATED);
            LOGGER.info("Zipping to : " + destinationZipFile);

            for (String entry : this.fileList) {
                long fileSizeInBytes = new File(sourceDirectory + 
                    File.separator + entry).length();

                if(new File(sourceDirectory + File.separator + entry).isFile()) {
                    LOGGER.info("File Added : " + entry + " ("+String.valueOf(fileSizeInBytes)+" bytes)");
                    ZipEntry ze = new ZipEntry(entry);

                    zos.putNextEntry(ze);
                    FileInputStream in = new FileInputStream(sourceDirectory
                            + File.separator + entry);
                    int len;
                    while ((len = in.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }

                    in.close();
                    zos.closeEntry();

                } else if(new File(sourceDirectory  + File.separator + entry).isDirectory()) {
                    LOGGER.info("Directory Added : " + entry);
                    ZipEntry ze = new ZipEntry(entry+File.separator);
                    zos.putNextEntry(ze);
                    zos.closeEntry();
                } else {
                    LOGGER.warn("Not a file or directory: "+entry);
                }
            }

            zos.closeEntry();
            zos.close();

            LOGGER.info("Zipping completed successfully");
        } catch (IOException ex) {
            LOGGER.error(ex);
            System.exit(1);
        }
        LOGGER.info("Generated zip file: "+ destinationZipFile);
    }


    /**
     * Format the filename for archiving by removing the path
     * of the source directory
     * 
     * @param file
     * @return
     */
    private String generateZipEntry(String file) {
        LOGGER.debug("Stripping '"+file+"' to '"
            +file.substring(sourceDirectory.length() + 1, file.length())+"'");
        return file.substring(sourceDirectory.length() + 1, file.length());
    }

}

所以我在 WinZip 中生成的 zip 文件诊断中看到的输出如下:


非工作文件

Archive: C:\Users\conor\Desktop\dp-export-2\dp-export-2.zip   3573 bytes   2014-11-04 20:03:22
Current Location part 1 offset 3551
End central directory record PK0506 (4+18)
==========================================
    location of end-of-central-dir record:          3551 (0x00000ddf) bytes
    part number of this part (0000):                1
    part number of start of central dir (0000):     1
    number of entries in central dir in this part:  1
    total number of entries in central dir:         1
    size of central dir:                            56 (0x00000038) bytes
    relative offset of central dir:                 3495 (0x00000da7) bytes
    zipfile comment length:                         0

Current Location part 1 offset 3495
Central directory entry PK0102 (4+42): #1
======================================
    part number in which file begins (0000):        1
    relative offset of local header:                0 (0x00000000) bytes
    version made by operating system (00):          MS-DOS, OS/2, NT FAT
    version made by zip software (20):              2.0
    operat. system version needed to extract (00):  MS-DOS, OS/2, NT FAT
    unzip software version needed to extract (20):  2.0
    general purpose bit flag (0x0808) (bit 15..0):  0000.1000 0000.1000
      file security status  (bit 0):                not encrypted
      extended local header (bit 3):                yes
      UTF-8 names          (bit 11):                yes
    compression method (08):                        deflated
      compression sub-type (deflation):             normal
    file last modified on (0x00004564 0x0000a06a):  2014-11-04 20:03:20
    32-bit CRC value:                               0x07d797c8
    compressed size:                                3439 bytes
    uncompressed size:                              24021 bytes
    length of filename:                             10 characters
    length of extra field:                          0 bytes
    length of file comment:                         0 characters
    internal file attributes:                       0x0000
      apparent file type:                           binary
    external file attributes:                       0x00000000
      non-MSDOS external file attributes:           0x000000
      MS-DOS file attributes (0x00):                none
    filename: export.xml

Current Location part 1 offset 0
Local directory entry PK0304 (4+26): #1
------------------------------------
    operat. system version needed to extract (00):  MS-DOS, OS/2, NT FAT
    unzip software version needed to extract (20):  2.0
    general purpose bit flag (0x0808) (bit 15..0):  0000.1000 0000.1000
      file security status  (bit 0):                not encrypted
      extended local header (bit 3):                yes
      UTF-8 names          (bit 11):                yes
    compression method (08):                        deflated
      compression sub-type (deflation):             normal
    file last modified on (0x00004564 0x0000a06a):  2014-11-04 20:03:20
    32-bit CRC value:                               0x00000000
    compressed size:                                0 bytes
    uncompressed size:                              0 bytes
  note: "real" crc and sizes are in the extended local header
    length of filename:                             10 characters
    length of extra field:                          0 bytes
    filename: export.xml

Testing export.xml   OK

Current Location part 1 offset 3479
Extended local dir entry PK0708 (4+12): #1
---------------------------------------
    32-bit CRC value:                               0x07d797c8
    compressed size:                                3439 bytes
    uncompressed size:                              24021 bytes

No errors detected in compressed data of C:\Users\conor\Desktop\dp-export-2\dp-export-2.zip.

从非工作文件的解压缩中重新压缩的工作文件

Archive: C:\Users\conor\Desktop\dp-export-2\dp-export-2b.zip   3564 bytes   2014-11-04 20:04:46
Current Location part 1 offset 3542
End central directory record PK0506 (4+18)
==========================================
    location of end-of-central-dir record:          3542 (0x00000dd6) bytes
    part number of this part (0000):                1
    part number of start of central dir (0000):     1
    number of entries in central dir in this part:  1
    total number of entries in central dir:         1
    size of central dir:                            92 (0x0000005c) bytes
    relative offset of central dir:                 3450 (0x00000d7a) bytes
    zipfile comment length:                         0

Current Location part 1 offset 3450
Central directory entry PK0102 (4+42): #1
======================================
    part number in which file begins (0000):        1
    relative offset of local header:                0 (0x00000000) bytes
    version made by operating system (00):          MS-DOS, OS/2, NT FAT
    version made by zip software (20):              2.0
    operat. system version needed to extract (00):  MS-DOS, OS/2, NT FAT
    unzip software version needed to extract (20):  2.0
    general purpose bit flag (0x0002) (bit 15..0):  0000.0000 0000.0010
      file security status  (bit 0):                not encrypted
      extended local header (bit 3):                no
    compression method (08):                        deflated
      compression sub-type (deflation):             maximum
    file last modified on (0x00004564 0x0000a06a):  2014-11-04 20:03:20
    32-bit CRC value:                               0x07d797c8
    compressed size:                                3410 bytes
    uncompressed size:                              24021 bytes
    length of filename:                             10 characters
    length of extra field:                          36 bytes
    length of file comment:                         0 characters
    internal file attributes:                       0x0001
      apparent file type:                           text
    external file attributes:                       0x00000020
      non-MSDOS external file attributes:           0x000000
      MS-DOS file attributes (0x20):                arc
    filename: export.xml
    extra field 0x000a (PKWARE Win32 Filetimes), 4 header and 32 data bytes:
    The Extended Timestamps are:
      Creation Date:                                2014-11-04 20:03:20
      Last Modified Date:                           2014-11-04 20:03:20
      Last Accessed Date:                           2014-11-04 20:03:20

Current Location part 1 offset 0
Local directory entry PK0304 (4+26): #1
------------------------------------
    operat. system version needed to extract (00):  MS-DOS, OS/2, NT FAT
    unzip software version needed to extract (20):  2.0
    general purpose bit flag (0x0002) (bit 15..0):  0000.0000 0000.0010
      file security status  (bit 0):                not encrypted
      extended local header (bit 3):                no
    compression method (08):                        deflated
      compression sub-type (deflation):             maximum
    file last modified on (0x00004564 0x0000a06a):  2014-11-04 20:03:20
    32-bit CRC value:                               0x07d797c8
    compressed size:                                3410 bytes
    uncompressed size:                              24021 bytes
    length of filename:                             10 characters
    length of extra field:                          0 bytes
    filename: export.xml

Testing export.xml   OK

No errors detected in compressed data of C:\Users\conor\Desktop\dp-export-2\dp-export-2b.zip.

很明显,我可以在输出中看到差异,但我不明白为什么所有差异都存在,也不知道哪一个是导致失败的原因。在确定为什么我的目标应用程序可能不喜欢 Java 生成的文件的任何帮助将是一个很大的帮助。我有一种暗示,原因是 Java 与 WinZip 计算 CRC 并随后添加到存档中的方式,但我没有遇到此类问题。我的另一个理论是,这是由于内部文件属性。无法解析的示例将“export.xml”显示为二进制数据,但 WinZip 版本将其显示为文本。

【问题讨论】:

  • 关于目标应用程序中发生的错误的更多信息?
  • 不幸的是,它告诉我的是它无法解析 zip 文件。就其价值而言,它实际上是一个 IBM DataPower 设备。所以是该设备上的固件无法解析文件。
  • 一些建议:尝试使用非常简单的文件结构——一个文件是一个好的开始。您可以访问 Unix 吗?尝试使用 unzip 获取 zip 与 winzip zip 中的文件列表。尝试将压缩级别设置为 0。fileanalysis.net/zip 提供有关 zip 文件格式的信息。
  • 我尝试了压缩级别 0,也尝试了只使用一个文件并相应地更新了我提供的示例。我通过使用 Apache commons compress library 解决了这个问题。我将在下面发布我的解决方案

标签: java zip


【解决方案1】:

我解决了这个问题,我不明白根本原因是什么,但是通过使用 org.apache.commons.compress 库,zip 文件现在可以使用。明天我会再次深入研究它,因为我很想知道有什么区别。同时,这是更新后的课程。

package com.mycompany.utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.log4j.Logger;

public class FileZipper {

    private static final Logger LOGGER = Logger.getLogger(OldFileZipper.class);
    private String destinationZipFile;
    private String sourceDirectory;

    List<String> fileList;
    private File zipFile;

    public File getZipFile() {
        return zipFile;
    }

    /**
     * Zips a source directory into the destination zip file
     * 
     * @param source
     * @param destination
     */
    FileZipper(String source, String destination) {
        LOGGER.info("Zipping source directory: "+source);
        LOGGER.info("To destination zip file:  "+destination);
        this.destinationZipFile = destination;
        this.sourceDirectory = source;
        fileList = new ArrayList<String>();
        generateFileList(new File(sourceDirectory));
        compressDirectoryContentsToZip(sourceDirectory, destinationZipFile);
    }

    /**
     * Traverse a directory and get all files, and add the file into fileList
     * 
     * @param node
     *            file or directory
     */
    public void generateFileList(File node) {

        // add file only
        if (node.isFile()) {
            fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
        }

        if (node.isDirectory()) {
            if(node.toString() != sourceDirectory) {
                fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
            }
            String[] subNodes = node.list();
            for (String filename : subNodes) {
                generateFileList(new File(node, filename));
            }
        }

    }

    /**
     * Compress a directory to a zip file
     * @param sourceDirectory
     * @param destinationZipFile
     */
    public void compressDirectoryContentsToZip(String sourceDirectory, String destinationZipFile) {

        this.zipFile = new File(destinationZipFile);

        byte[] buffer = new byte[4096];

        try {

            FileOutputStream fos = new FileOutputStream(destinationZipFile);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            ZipArchiveOutputStream zos = new ZipArchiveOutputStream(bos);
            zos.setMethod(ZipArchiveOutputStream.DEFLATED);
            zos.setLevel(0);
            LOGGER.info("Zipping to : " + destinationZipFile);

            for (String entry : this.fileList) {
                long fileSizeInBytes = new File(sourceDirectory + File.separator + entry).length();

                if(new File(sourceDirectory + File.separator + entry).isFile()) {
                    LOGGER.info("File Added : " + entry + " ("+String.valueOf(fileSizeInBytes)+" bytes)");
                    ZipArchiveEntry ze = new ZipArchiveEntry(entry);
                    zos.putArchiveEntry(ze);
                    FileInputStream in = new FileInputStream(sourceDirectory
                            + File.separator + entry);
                    int len;
                    while ((len = in.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }

                    in.close();
                    zos.closeArchiveEntry();

                } else if(new File(sourceDirectory  + File.separator + entry).isDirectory()) {
                    LOGGER.info("Directory Added : " + entry);
                    ZipArchiveEntry ze = new ZipArchiveEntry(entry+File.separator);
                    zos.putArchiveEntry(ze);
                    zos.closeArchiveEntry();
                } else {
                    LOGGER.warn("Not a file or directory: "+entry);
                }
            }

            zos.close();

            LOGGER.info("Zipping completed successfully");
        } catch (IOException ex) {
            LOGGER.error(ex);
            System.exit(1);
        }
        LOGGER.info("Generated zip file: "+ destinationZipFile);
    }


    /**
     * Format the filename for archiving by removing the path
     * of the source directory
     * 
     * @param file
     * @return
     */
    private String generateZipEntry(String file) {
        LOGGER.debug("Stripping '"+file+"' to '"+file.substring(sourceDirectory.length() + 1, file.length())+"'");
        return file.substring(sourceDirectory.length() + 1, file.length());
    }

}

【讨论】:

  • 我遇到了完全相同的问题(虽然使用不同的系统),但您的解决方案效果很好。你发现有什么不同吗?
  • 是很久以前的事了,记不得了
  • 太糟糕了,我也很好奇。还是谢谢!
猜你喜欢
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多