【问题标题】:Java UTF-8 non ASCII chars not supported on WindowsWindows 不支持 Java UTF-8 非 ASCII 字符
【发布时间】:2021-10-27 05:54:34
【问题描述】:

我正在开发一种工具,该工具可以生成包含一些生成文件的 zip。我的一些使用 Windows 10 的用户报告说,当我将字符串添加到 zip 中的文件中时,非 ascii 字符被替换为“?” 这真的很奇怪,因为它在 linux (nixos) 上完美运行。你有什么想法吗?

fis = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));

...

    public static void addToZip(String zipFilePath, final InputStream fis, final ZipOutputStream zos)
            throws IOException {
        final ZipEntry zipEntry = new ZipEntry(zipFilePath);
        zipEntry.setLastModifiedTime(FileTime.fromMillis(0L));
        zos.putNextEntry(zipEntry);

        final byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0)
            zos.write(bytes, 0, length);

        zos.closeEntry();
        fis.close();
        if (!(Settings.PROTECTION.toBool()))
            return;
        zipEntry.setCrc(bytes.length);
        zipEntry.setSize(new BigInteger(bytes).mod(BigInteger.valueOf(Long.MAX_VALUE)).longValue());
    }

...

  final ZipOutputStream zos = new ZipOutputStream(fos, StandardCharsets.UTF_8);

【问题讨论】:

  • ZipOutputStream 带有字符编码?该类在哪个包中?
  • 他们如何检查这个以查看“?”?
  • 他们很可能会保存他们的文件 windows-1252 编码并且您正在阅读 utf_8 样式。
  • @g00se 我猜它是Java中的那个,见ZipOutputStream​(OutputStream out, Charset charset)
  • zipEntry.setCrc(bytes.length); 毫无意义。那不是该领域的用途。也就是说,您需要提供一个 minimal reproducible example 来实际演示问题。

标签: java unicode ascii


【解决方案1】:

由于您的描述和代码不完整,我做一些假设:

  • zip 存档中的某些文件是文本文件(或类似的文件,例如 CSV)。
  • zip 存档是在 Linux 系统(或您控制的单个系统)上创建的。
  • zip 存档会发送给您的用户,然后用于不同的操作系统。

如果是这样,则问题与 zip 存档无关。相反,这是文本文件的普遍问题。如果您只发送一个文本文件,也会发生这种情况。

问题的原因是文本文件不包含任何关于编码的可靠信息。在您这边,文本文件是使用 UTF-8 编码创建的。在用户方面,使用不同的操作系统和不同的工具来查看或处理文本文件。其中一些工具可能会努力确定编码并正确猜测。但是如果他们只是使用操作系统的默认编码,Windows用户会使用不正确的编码,因为Windows默认为Windows-1252和类似的编码。

使用 Windows-1252 编码处理 UTF-8 编码文件的结果是,在 Windows-1252 中无效的字节显示为“?”。

如果您的用户使用文本编辑器查看文本文件,请让他们将文本编辑器设置为 UTF-8。如果使用自定义软件处理文本文件,请要求他们修改软件,使其明确使用 UTF-8。

【讨论】:

  • 生成的 zip 存档中的一些文件是文本文件(实际上是 json 文件)。给定一个内容字符串,这就是我获取输入流的方式:new ByteArrayInputStream(content.getBytes()))。 zip 存档是在用户操作系统上创建的(我发送的代码是生成它的代码)。此 zip 存档在 Windows 上未正确创建(编码问题),但它在 linux 上完美运行。如果生成的文件是在 linux 上生成的,则生成的文件在两个操作系统上都可以工作,但如果它是在 windows 上生成的,则根本不工作。
  • content.getBytes() 可能是问题,因为它使用默认编码。奇怪的是,这与您在问题中显示的内容相矛盾。请更新您的问题,以便我们了解 content 是什么(字符串?)、它是如何生成的(它可能已经包含损坏的数据)以及它是如何用于生成 zip 存档的。
  • 我不明白,我的问题中的矛盾在哪里,我应该编辑什么?我认为content.getBytes() 是问题所在,因为content.getBytes(StandardCharsets.UTF_8) 似乎已经修复了它。我让 Windows 上的用户试用这个自定义版本,它正在工作,我会尝试联系其他一些人。
  • 问题显示content.getBytes(StandardCharsets.UTF_8)。所以你问了一个已经默默包含修复的问题。您到底希望我们做什么?
  • 对不起。我没有注意到我确实发布了这个。我实际上使用了两个不同的输入流。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 1970-01-01
  • 2017-11-10
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多