【问题标题】:Unable to use encoding UTF-16LE on Android Version 9无法在 Android 版本 9 上使用编码 UTF-16LE
【发布时间】:2021-07-05 02:55:45
【问题描述】:

我有一个创建 csv 文件的应用程序。然后由 excel makro 导入该文件。 makro 需要使用 UTF-16LE 编码对文件进行编码。问题是,我无法在某些设备上使用此编码。

到目前为止,我使用字符集 UTF-16 来创建文件。当我用记事本++打开文件时,它显示文件是用UTF-16LE编码的。现在我有一个新设备,当我用它创建 csv 文件时,notepad++ 显示编码是 UTF-16BE。结果,当我尝试使用 excel makro 导入文件时出现错误。

我尝试将编码指定为 UTF-16LE,根据 android 的 developer page,它应该是一个有效的字符集。但是notepad++无法识别我文件的编码,excel makro无法读取它(对于旧设备和新设备)。

我可以通过 notepad++ 将这两种情况下的编码转换为 UTF-16LE,并使用我的 makro 成功导入文件,但我需要从我的应用程序中以正确的格式创建文件。

旧设备的安卓版本5.1

较新的设备有安卓版本9.0

这是我的代码:

File file = new File("some_name");
if (file.exists()) {
    file.delete();
}
file.getParentFile().mkdirs();
file.createNewFile();

Writer osw = new OutputStreamWriter(new FileOutputStream(file),"UTF-16LE"); //Or "UTF-16"
osw.write("foo");
osw.write("bar");
osw.close();

如何在新设备上使用 UTF-16LE 编码?


我确实看过this answere 并像这样实现它:

Writer osw = new OutputStreamWriter(new FileOutputStream(file),"UTF-16LE"); //Or "UTF-16"
osw.write(new String(("foo").getBytes("UTF-16LE"), "UTF-16LE"));
osw.write(new String(("bar").getBytes("UTF-16LE"), "UTF-16LE"));
osw.close();

我也使用了StandardCharsets.UTF_16LE,但它并没有改变任何东西。编码仍然无法被notepad++识别,也没有被makro导入。

【问题讨论】:

  • 你见过:Showing a UTF16-LE encoded string in textview for Android,即确保你正在编写 UTF16-LE 字符串
  • 建议使用StandardCharsets.UTF_16LE,而不是将编码作为字符串提供。
  • @MorrisonChang 我已经尝试了这两个建议,遗憾的是这并没有改变任何东西:/我已经更新了我的问题。
  • 运行 Android 9.0 的较新设备是什么?
  • Android 9 中的 UTF 解码器行为发生了变化(请参阅 here)。创建 CSV 文件的数据来源是什么?

标签: java android encoding character-encoding utf-16le


【解决方案1】:

您可以尝试使用指定编码的字节顺序标记 (bom) 显式强制 UTF-16LE 编码。 Notepad++ 和 Excel 都可以解释 bom。例如,以下代码将生成一个适合使用字节顺序标记导入 Excel 的 csv 文件:

public void writeFile(Context context) throws IOException {
    File file = new File(context.getFilesDir(), "some_name.csv");
    if (file.exists()) file.delete();

    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_16LE);

    // The byte order mark for UTF-16 is "\ufeff" but will appear as "\ufffe" when
    // the file is UTF-16LE.
    osw.write("\ufeff");
    osw.write("Header1,Header2,Header3,Header4\n");
    osw.write("text1,text2,text3,text4\n");
    osw.write("text5,text6,text7,text8");
    osw.close();
}

在 Android 9 模拟器上生成的文件如下所示:

PS C:\> format-hex some_name.csv

           Path: C:\some_name.csv

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   FF FE 48 00 65 00 61 00 64 00 65 00 72 00 31 00  .þH.e.a.d.e.r.1.
00000010   2C 00 48 00 65 00 61 00 64 00 65 00 72 00 32 00  ,.H.e.a.d.e.r.2.
00000020   2C 00 48 00 65 00 61 00 64 00 65 00 72 00 33 00  ,.H.e.a.d.e.r.3.
00000030   2C 00 48 00 65 00 61 00 64 00 65 00 72 00 34 00  ,.H.e.a.d.e.r.4.
00000040   0A 00 74 00 65 00 78 00 74 00 31 00 2C 00 74 00  ..t.e.x.t.1.,.t.
00000050   65 00 78 00 74 00 32 00 2C 00 74 00 65 00 78 00  e.x.t.2.,.t.e.x.
00000060   74 00 33 00 2C 00 74 00 65 00 78 00 74 00 34 00  t.3.,.t.e.x.t.4.
00000070   0A 00 74 00 65 00 78 00 74 00 35 00 2C 00 74 00  ..t.e.x.t.5.,.t.
00000080   65 00 78 00 74 00 36 00 2C 00 74 00 65 00 78 00  e.x.t.6.,.t.e.x.
00000090   74 00 37 00 2C 00 74 00 65 00 78 00 74 00 38 00  t.7.,.t.e.x.t.8.

Notepad++ 像这样解释文件:

导入文件后Excel显示如下:

这并不能直接回答您的问题,但您应该能够将此代码与您的数据一起使用来帮助诊断问题。

我在评论中留下了这一点,但我会在这里再次提及:UTF 解码器的行为在 Android 9 中确实发生了变化,变得更加符合 Unicode 标准。这些更改在here 中进行了描述。不确定这会对您的情况产生什么影响(如果有的话),但值得一看(IMO)。

【讨论】:

  • 我试图通过手动将 BOM 添加到文件中来强制编码。虽然我使用 StandardCharset.UTF_16LE 输出仍然被识别为 UTF-8,但这次使用 BOM(UTF-8-BOM)。但令人惊讶的是,makro 能够读取该文件。也许 makro 不需要 UTF-16LE,但需要一些带有 BOM 的格式。你没有严格回答这个问题,但帮助我解决了我的潜在问题。我会接受这个答案并奖励你赏金。非常感谢!!
猜你喜欢
  • 2015-02-03
  • 1970-01-01
  • 2020-01-12
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 2010-10-27
  • 2018-06-23
  • 2018-07-18
相关资源
最近更新 更多