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

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

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

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

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

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

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

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

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

现在可以在创建 zip文件/流时设置文件名编码 ( 需要Java 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”)就足够了。

通过快速查看TrueZIP 手册 – 他们推荐JAR格式:

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

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

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

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

抱歉!