将非ASCII文件名添加到Java中的zip中
使用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(); } } }
解决方案
它真的失败了还是仅仅是字体问题? (例如,那些字符的字体具有不同的字形)在Windows中,由于字体不支持字符集,但数据实际上是完整无误的,因此在渲染"中断"时出现了类似的问题。
非ASCII文件名在ZIP实施中不可靠,最好避免使用。没有提供将字符集设置存储在ZIP文件中的规定;客户倾向于猜测"当前系统代码页",这不太可能是我们想要的。客户端和代码页的许多组合都可能导致文件无法访问。
对不起!
通过快速浏览TrueZIP手册,他们推荐了JAR格式:
It uses UTF-8 for file name encoding and comments - unlike ZIP, which only uses IBM437.
这可能意味着该API使用java.util.zip包进行了实现;该文档指出,从1996年开始,它仍在使用ZIP格式。直到2006年,才对PKWARE .ZIP文件格式规范添加了Unicode支持。
ZIP中File-Entries的编码最初指定为IBM Code Page437. 其他语言中使用的许多字符不可能以这种方式使用。
PKWARE规范提到了这个问题,并增加了一点。但这是后来添加的内容(从2007年开始,感谢Cheeso清除了该内容,请参阅评论)。如果该位置1,则文件名条目必须以UTF-8编码。此扩展在链接文档末尾的"附录D语言编码(EFS)"中进行了描述。
对于Java,使用非ASCII字符会遇到麻烦是一个已知的错误。请参阅错误#4244499和大量相关错误。
我的同事在将文件名存储到ZIP中并在读取文件后进行解码之前,将其用作URL编码的变通方法。如果同时控制存储和读取,则可能是一种解决方法。
编辑:在错误处,有人建议使用Apache Ant中的ZipOutputStream作为解决方法。此实现允许指定编码。
根据PKWare拥有的规范,在Zip文件中,文件名和文件注释的编码为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确实修复了长期存在的错误/ 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")应该足够了。