19

使用Java将非 ASCII文件名添加到zip 文件的最佳方法是什么,以便可以在WindowsLinux 中正确读取文件?

这是一种尝试,改编自https://truezip.dev.java.net/tutorial-6.html#Example,它适用于 Windows Vista 但在 Ubuntu Hardy 中失败。在 Hardy 中,文件名在 file-roller 中显示为 abc-ЖДФ.txt。

import java.io.IOException;
import java.io.PrintStream;

import de.schlichtherle.io.File;
import de.schlichtherle.io.FileOutputStream;

public class Main {

    public static void main(final String[] args) throws IOException {

        try {
            PrintStream ps = new PrintStream(new FileOutputStream(
                    "outer.zip/abc-åäö.txt"));
            try {
                ps.println("The characters åäö works here though.");
            } finally {
                ps.close();
            }
        } finally {
            File.umount();
        }
    }
}

与 java.util.zip 不同,truezip 允许指定 zip 文件编码。这是另一个示例,这次明确指定了编码。IBM437、UTF-8 和 ISO-8859-1 在 Linux 中都不起作用。IBM437 在 Windows 中工作。

import java.io.IOException;

import de.schlichtherle.io.FileOutputStream;
import de.schlichtherle.util.zip.ZipEntry;
import de.schlichtherle.util.zip.ZipOutputStream;

public class Main {

    public static void main(final String[] args) throws IOException {

        for (String encoding : new String[] { "IBM437", "UTF-8", "ISO-8859-1" }) {
            ZipOutputStream zipOutput = new ZipOutputStream(
                    new FileOutputStream(encoding + "-example.zip"), encoding);
            ZipEntry entry = new ZipEntry("abc-åäö.txt");
            zipOutput.putNextEntry(entry);
            zipOutput.closeEntry();
            zipOutput.close();
        }
    }
}
4

7 回答 7

10

ZIP 中文件条目的编码最初指定为 IBM Code Page 437。其他语言中使用的许多字符不可能以这种方式使用。

PKWARE-specification提到了这个问题并添加了一点。但这是后来添加的(从 2007 年开始,感谢 Cheeso 的清理,请参阅评论)。如果设置了该位,则文件名条目必须以 UTF-8 编码。此扩展在链接文档末尾的“附录 D - 语言编码 (EFS)”中进行了描述。

对于 Java,这是一个已知的错误,会遇到非 ASCII 字符的麻烦。请参阅错误 #4244499和大量相关错误。

我的同事在将文件名存储到 ZIP 并在读取文件后解码之前用作文件名的解决方法 URL-Encoding。如果您同时控制存储和读取,这可能是一种解决方法。

编辑:在错误中,有人建议使用 Apache Ant 的 ZipOutputStream 作为解决方法。此实现允许指定编码。

于 2008-10-14T11:38:46.793 回答
8

在 Zip 文件中,根据 PKWare 拥有的规范,文件名和文件注释的编码是 IBM437。2007 年,PKWare 扩展了规范,也允许使用 UTF-8。这并没有说明 zip 中包含的文件的编码。只有文件名的编码。

我认为所有工具和库(Java 和非 Java)都支持 IBM437(它是 ASCII 的超集),支持 UTF-8 的工具和库较少。一些工具和库支持其他代码页。例如,如果您在上海运行的计算机上使用 WinRar 压缩某些内容,您将获得 Big5 代码页。这不是 zip 规范“允许”的,但无论如何都会发生。

.NET的DotNetZip库支持 Unicode,但如果您使用 Java,这当然对您没有帮助!

使用对 ZIP 的 Java 内置支持,您将始终获得 IBM437。如果您想要一个包含 IBM437 以外的东西的存档,那么请使用第三方库,或者创建一个 JAR。

于 2009-01-04T03:49:48.107 回答
8

奇迹确实发生了,Sun/Oracle 确实修复了长期存在的错误/rfe:

现在可以在创建zip 文件/流时设置文件名编码(需要 Java 7)。

于 2010-07-28T11:26:52.740 回答
7

您仍然可以使用 Apache Commons 的 zip 流实现:http ://commons.apache.org/compress/apidocs/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.html#setEncoding%28java.lang.String %29

在您的流上调用 setEncoding("UTF-8") 就足够了。

于 2010-12-17T16:03:36.160 回答
3

快速浏览一下 TrueZIP手册- 他们推荐 JAR 格式:

它使用 UTF-8 进行文件名编码和注释 - 不像 ZIP,它只使用 IBM437。

这可能意味着 API 正在使用java.util.zip包来实现它;该文档指出,它仍然使用1996 年的 ZIP 格式。直到 2006 年,Unicode 支持才被添加到PKWARE .ZIP 文件格式规范中。

于 2008-09-20T00:09:01.750 回答
0

它真的失败了还是只是字体问题?(例如,这些字符代码具有不同字形的字体) 我在 Windows 中看到了类似的问题,因为字体不支持字符集,但数据实际上是完整且正确的。

于 2008-09-19T23:29:16.370 回答
0

非 ASCII 文件名在 ZIP 实现中不可靠,最好避免使用。没有规定在 ZIP 文件中存储字符集设置;客户倾向于猜测“当前系统代码页”,这不太可能是您想要的。客户端和代码页的许多组合可能会导致无法访问的文件。

对不起!

于 2008-09-19T23:47:22.083 回答