使用Java SE6时读取包含特殊字符的ZipEntry

时间:2013-01-07 12:55:32

标签: java character-encoding zip

使用解决方案更新,请参见底部

要求
在Java SE 6中处理ZIP文件,其中包含文件名中包含特殊字符的文件。由于(ZIP生产者)的编码不是UTF-8,因此特殊字符被编码。因此,我想将特殊字符更正为正确的代码。

问题
ZIP包含一个名为abcüabc.txt的文件。 该条目通过java.util.zip.ZipEntry处理,当打印出单个字符时,我看到这些字符(字节):

ü被编码为
u后跟一个 ¨

问题
所以我想知道如何将替换为üue

我已经尝试过但没有解决的问题:
name.replaceAll("u\\¨", "ue");

name.replaceAll("ü", "ue");

原始源代码(无效)

InputStream is = new FileInputStream(new File("/Users/me/Desktop/test.zip"));
ZipInputStream zipStream = new ZipInputStream(is);
ZipEntry zipEntry = null;
while ((zipEntry = zipStream.getNextEntry()) != null) {
    String name = zipEntry.getName(); // reading abcüabc.txt
    System.out.println("pos 3: "+name.charAt(3));
    System.out.println("pos 4: "+name.charAt(4));
    System.out.println("is equal to ¨: "+Character.toString(name.charAt(4)).equals("¨"));
}        

输出:

pos 3: u
pos 4:¨
is equal to ¨: false

关于我的环境的说明

在Mac OS X 10.6.8下生成的Zip Java SE 6:Java HotSpot(TM)64位服务器VM(版本20.12-b01-434,混合模式)

解决方案

显然,ZIP制作人(在我的Mac OSX中)将特殊字符转换为分解格式。因此ü会被分解为 从ZIP中提取文件名时,我们希望从分解格式转换回组合格式,因此我们只需要在上面的源代码中插入规范化:

InputStream is = new FileInputStream(new File("/Users/me/Desktop/test.zip"));
ZipInputStream zipStream = new ZipInputStream(is);
ZipEntry zipEntry = null;
while ((zipEntry = zipStream.getNextEntry()) != null) {
    String name = zipEntry.getName(); // reading abcüabc.txt
    System.out.println("pos 3: "+name.charAt(3));
    System.out.println("pos 4: "+name.charAt(4));
    System.out.println("contains ü: "+name.contains("ü"));
    name = Normalizer.normalize(name, Form.NFC);
    System.out.println("contains ü: "+name.contains("ü"));
}        

输出:

pos 3: u
pos 4:¨
contains ü: false
contains ü: true

2 个答案:

答案 0 :(得分:3)

这不是¨U+00A8 DIAERESIS),而是U+0308 COMBINING DIAERESIS

字符以这种方式分割,因为Mac Os将文件名存储在规范化表格D中,它会像这样分解字符。

你可以像这样编曲:

String name = zipEntry.getName(); 
name = Normalizer.normalize(name, Form.NFC);

有关normalization forms

的更多信息

diaeresises之间的区别在于他们如何修改或不修改以前的基本字符:

    System.out.println( "u" + (char)0xA8); //u¨
    System.out.println( "u" + (char)0x0308); //ü

答案 1 :(得分:0)

您可以使用apache ant解决编码问题。

导入org.apache.tools.zip.*

ZipFile zipFile = new ZipFile(fileName,"you encoding");// you encoding like utf-8 
Enumeration emu = zipFile.getEntries();


while(emu.hasMoreElements()){
  ZipEntry entry = (ZipEntry) emu.nextElement();
  // do something
}

Ant项目不提供在线文档,这是另一个文档http://api.dpml.net/ant/1.7.0/