在 Java 中添加非 ASCII 文件名以压缩

2022-09-02 12:21:09

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

这是一个尝试,改编自 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();
        }
    }
}

答案 1

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

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

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

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

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


答案 2

在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。


推荐