在Java中以zip方式添加非ASCII文件名

时间:2008-09-19 23:25:25

标签: java encoding zip

使用 Java 非ASCII 文件名添加到 zip文件的最佳方法是什么,以这种方式使用文件可以在 Windows Linux?

中正确阅读

这是一次改编自https://truezip.dev.java.net/tutorial-6.html#Example的尝试,它在Windows Vista中运行但在Ubuntu Hardy中失败。在Hardy中,文件名在文件夹中显示为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();
        }
    }
}

7 个答案:

答案 0 :(得分:10)

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

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

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

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

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

答案 1 :(得分:8)

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

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

.NET的DotNetZip库执行Unicode,但是如果您使用Java,这对您没有帮助!

使用Java内置的ZIP支持,您将始终获得IBM437。如果您希望使用IBM437之外的其他内容存档,则使用第三方库,或创建JAR。

答案 2 :(得分:8)

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

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

答案 3 :(得分:7)

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

在您的信息流上调用setEncoding(“UTF-8”)就足够了。

答案 4 :(得分:3)

快速查看TrueZIP manual - 他们推荐使用JAR格式:

  

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

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

答案 5 :(得分:0)

它真的失败了还是只是一个字体问题? (例如,字体对于那些字符有不同的字形)我在Windows中看到类似的问题,渲染“破坏”,因为字体不支持字符集,但数据实际上是完整和正确的。

答案 6 :(得分:0)

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

抱歉!