【问题标题】:"IllegalArgumentException: UNMAPPABLE[1]" while zipping a file with Greek characters“IllegalArgumentException:UNMAPPABLE [1]”在压缩带有希腊字符的文件时
【发布时间】:2014-07-10 03:02:39
【问题描述】:

我想在 Windows (7) 上使用 ZipOutputStream 压缩文件。问题是文件名(以及文件文件内容)还包含希腊字符(“ГП0000660040140521_a.txt”、Gamma 和 Pi)。我使用的压缩文件的代码:

ZipOutputStream zipOs = new ZipOutputStream(
    new FileOutputStream("c:\\temp\\test.zip"), Charset.forName("cp737")
);

File sourceFile = new File("C:/Path/To/File/ГП0000660040140521_b.txt");
String entryName = sourceFile.getName().replaceAll("\\\\", "/");
ZipEntry entry = new ZipEntry(entryName);
zipOs.putNextEntry(entry);
...
...

但在最后一行(putNextEntry 调用)我得到一个IllegalArgumentException

java.lang.IllegalArgumentException: UNMAPPABLE[1]
at java.util.zip.ZipCoder.getBytes(ZipCoder.java:95)
at java.util.zip.ZipOutputStream.writeLOC(ZipOutputStream.java:407)
at java.util.zip.ZipOutputStream.putNextEntry(ZipOutputStream.java:221)

我认为希腊语和 UTF-8 之间的字符映射一定有什么问题......压缩文件名中包含希腊字符的文件的正确方法是什么?

编辑

如果我使用“utf-8”作为字符集,可以创建压缩文件,但是压缩文件的名称是错误的:“ðôðƒ0000660040140521_a.txt”(缺少希腊字符)

【问题讨论】:

  • createZipEntry 方法有什么作用?
  • @agad:我的错!我已经更正了代码。谢谢。
  • 当你说名字是“错误的”时,你究竟是如何验证这一点的?您使用哪个工具来检查 ZIP 文件,您确定该工具使用与创建文件名时相同的编码来解释文件名吗?
  • 用Windows的文件资源管理器打开。您的意思是,文件名是正确的,但 Windows 资源管理器显示错误?但为什么 Windows 文件资源管理器显示原始文件的 Creek 字符正确?
  • 在 Java 代码中使用 UTF-8 时无法重现该问题。我在德语 Windows (cp850) 上尝试过,创建了一个文件 όνομα_αρχείου.txt,然后从 Java 8 中压缩它。ZIP 文件中的文件名是正确的,我只在使用其他东西时遇到问题代码中的 UTF-8。所以我需要更多关于你是如何做到这一点的信息。

标签: java character-encoding zipoutputstream


【解决方案1】:

由于我的问题的“味噌”和“kriegax”的cmets,我写了这个(迟到的)答案。

如果我没记错的话,我在任何地方都读到过,zip 文件中文件名的 UTF8 支持是 zip 文件的一大弱点(因为 UTF-8 不是 zip 标准的官方支持?!?)。现在可能是现有的 zip 应用程序在文件名中支持 UTF-8。

但是。在我们的例子中,我们可以用“普通”字符(“a...z”)替换希腊字符,因为要压缩的文件是由财务打印机生成的,并且在每种情况下都只包含一个希腊字符:一个“PI”(只是一种解决方法......)。

【讨论】:

  • ZIP 的实际问题是它不携带有关用于对文件名进行编码的实际编码(字符集)的任何元信息。
【解决方案2】:

问题是,CP-737 确实是一个包含希腊字符的代码页,但是在 Java NIO 中,字符集的名称是 x-IBM737。参照。 http://docs.oracle.com/javase/7/docs/technotes/guides/intl/encoding.doc.html

【讨论】:

    【解决方案3】:

    由于ZipOutputStream 使用的ZipCoder 使用了一个映射器,该映射器配置为在无法映射字符时总是抛出异常,我最终自己先将entryName 转换为指定的字符集,然后调用ZipEntry entry = new ZipEntry(entryName) .例如,您可以这样做:

    new String(input.getBytes(charset), charset)
    

    这确保了所有不可篡改的字符都被转换为替换字符,并且没有异常。

    试试这个,您可能会注意到原始输入中有一些 Unicode 控制字符(不可映射)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 2012-03-17
      相关资源
      最近更新 更多