【问题标题】:Add non-ASCII file names to zip in Java在 Java 中将非 ASCII 文件名添加到 zip
【发布时间】:2008-09-19 23:25:24
【问题描述】:

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

【问题讨论】:

标签: java encoding zip


【解决方案1】:

ZIP 中 File-Entries 的编码最初指定为 IBM Code Page 437。其他语言中使用的许多字符无法以这种方式使用。

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

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

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

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

【讨论】:

  • “似乎在历史上被指定为 IBM CP437”有点松散。 PKWare 规范说文件名使用 IBM437 进行编码,句号。 2007 年,PKWare 添加了一种使用 UTF-8 的标准方式。有些工具两者都不使用,但这超出了规范!
  • 感谢您的澄清,我更改了答案。
  • 您写道“如果设置了该位,则所有文件名条目都必须以 UTF-8 编码”。这是不正确的。 UTF-8 或 IBM437 的使用是针对每个条目的,而不是针对每个归档的。符合规范的 zip 文件可以包含一些名称以 UTF-8 编码的条目和其他以 IBM437 编码的条目。
  • 为了增加混淆,德国安装的 Windows 将使用 cp850 解压档案。欢乐时光。
【解决方案2】:

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

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

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

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

【讨论】:

  • 为什么匿名投反对票?你不喜欢准确的信息吗?
  • 我仍然不确定为什么这个答案被否决。它仍然准确无误的信息。如果有人有任何异议,或者有人认为此答案中的信息有误,请说出来。
【解决方案3】:

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

现在可以set up filename encodings upon creating 压缩文件/流(需要 Java 7)。

【讨论】:

【解决方案4】:

您仍然可以使用 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") 就足够了。

【讨论】:

    【解决方案5】:

    快速浏览 TrueZIP manual - 他们推荐 JAR 格式:

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

    这可能意味着 API 正在使用 java.util.zip 包来实现它;该文档指出它仍在使用ZIP format from 1996。 Unicode 支持直到 2006 年才添加到 PKWARE .ZIP File Format Specification

    【讨论】:

      【解决方案6】:

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

      【讨论】:

      • 感谢您的回复,这不是字体问题,因为我可以创建一个类似名称的文件,然后将其压缩,它会正常显示。
      【解决方案7】:

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

      对不起!

      【讨论】:

      • 根据 PKWare 的规范,有一条规定要注意有问题的文件名是用 UTF-8 编码的。尚未广泛支持 zip 文件中的 UTF-8 编码(== Windows 资源管理器尚不支持)。当 zip 条目标头中未设置 UTF-8 位时,zip 规范表明文件名应该以 IBM437 编码。但你是对的,一些应用程序(WinRar)只是使用系统默认代码页进行编码。不确定 Windows 资源管理器是否这样做。读取 zip 文件时未使用正确的编码实际上会导致文件无法访问。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多