Java压缩文件的字符编码问题

5

我正在使用以下方法将文件压缩成zip文件:

import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public static void doZip(final File inputfis, final File outputfis) throws IOException {

    FileInputStream fis = null;
    FileOutputStream fos = null;

    final CRC32 crc = new CRC32();
    crc.reset();

    try {
        fis = new FileInputStream(inputfis);
        fos = new FileOutputStream(outputfis);
        final ZipOutputStream zos = new ZipOutputStream(fos);
        zos.setLevel(6);
        final ZipEntry ze = new ZipEntry(inputfis.getName());
        zos.putNextEntry(ze);
        final int BUFSIZ = 8192;
        final byte inbuf[] = new byte[BUFSIZ];
        int n;
        while ((n = fis.read(inbuf)) != -1) {
            zos.write(inbuf, 0, n);
            crc.update(inbuf);
        }
        ze.setCrc(crc.getValue());
        zos.finish();
        zos.close();
    } catch (final IOException e) {
        throw e;
    } finally {
        if (fis != null) {
            fis.close();
        }
        if (fos != null) {
            fos.close();
        }
    }
}

我的问题是,我有一些平面文本文件,其中包含内容 N°TICKET,例如,压缩后解压缩的结果会出现一些奇怪的字符 N° TICKET。另外,像 éà 这样的字符也不被支持。

我猜这是由于字符编码导致的,但我不知道如何在我的 zip 方法中设置它为 ISO-8859-1?

(我正在运行 Windows 7,Java 6)


1
你正在使用同一个编辑器查看预压缩和后压缩文件,对吗? - Wug
@fvu:问题出在文件内容,而不是文件名。 - Wug
为什么你使用流而不是写入器/读取器?流不知道字符或它们的编码。 - Dunes
@Wug 你说得对!实际上这是一个CSV文件,所以我用Excel查看了压缩后的文件... :-/ 所以我认为这是一个Excel问题。 - Majid Laissi
@Wug 但是根据Dunes的回答建议,将 Charset.forName("ISO-8859-1") 添加到我的输出写入器中解决了这个问题(Excel显示了正确的值)。 - Majid Laissi
也许这可以帮助,它使用ApacheCommons-compress库来解决JDK6问题https://dev59.com/h2bWa4cB1Zd3GeqPZrnQ#20523390 - Whome
3个回答

6

您正在使用流来精确写入给定的字节。Writer 解释字符数据并将其转换为相应的字节,而Reader则相反。Java(至少在版本6中)没有提供一种简单的方法来混合和匹配对压缩数据进行操作以及编写字符。

但是,以下方法可以实现。然而,它有点笨拙。

File inputFile = new File("utf-8-data.txt");
File outputFile = new File("latin-1-data.zip");

ZipEntry entry = new ZipEntry("latin-1-data.txt");

BufferedReader reader = new BufferedReader(new FileReader(inputFile));

ZipOutputStream zipStream = new ZipOutputStream(new FileOutputStream(outputFile));
BufferedWriter writer = new BufferedWriter(
    new OutputStreamWriter(zipStream, Charset.forName("ISO-8859-1"))
);

zipStream.putNextEntry(entry);

// this is the important part:
// all character data is written via the writer and not the zip output stream
String line = null;
while ((line = reader.readLine()) != null) {
    writer.append(line).append('\n');
}
writer.flush(); // i've used a buffered writer, so make sure to flush to the
// underlying zip output stream

zipStream.closeEntry();
zipStream.finish();

reader.close(); 
writer.close();

感谢将 Charset.forName("ISO-8859-1") 添加到我的 BufferedWriter 中,问题得到了解决。 - Majid Laissi
同样在这里,ISO-8859-1 对于 法语 口音也有效。谢谢。 - WannaGetHigh
在我的情况下,我可以生成没有编码问题的zip文件,但是我无法正确读取生成的zip文件中的欧洲字符。我使用了“ISO-8859-1”的InputStreamReader,它可以正常工作。任何人都可以在此处找到可用的代码示例https://gist.github.com/kairos34/75f782b029540e60c2f3b69e5166588e - Alper Özaslan

4

问题在输出文件而不是输入文件,在@Wug指出的评论中,它不是文件本身,而是Excel显示正确的编码,我不知道为什么... - Majid Laissi

0
尝试使用org.apache.commons.compress.archivers.zip.ZipFile而不是Java自带的库,这样你就可以像这样指定编码方式:
import org.apache.commons.compress.archivers.zip.ZipFile;
ZipFile zipFile = new ZipFile(filepath, encoding);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接