Linux 使用命令 file -i 为 windows-1252 编码文件返回错误值 charset=unknow-8bit

问题描述

使用 nodejs 和 iconv-lite 在 xml 中创建一个字符集为 windows-1252 的 http 响应文件,file -i 命令无法将其识别为 windows-1252。

服务器端:

r.header('Content-disposition','attachment; filename=teste.xml');
r.header('Content-Type','text/xml; charset=iso8859-1');
r.write(ICONVLITE.encode(`<?xml version="1.0" encoding="windows-1252"?><x>€Àáção</x>`,"win1252")); //euro symbol and portuguese accentuated vogals
r.end();

浏览器下载文件,然后我在 Ubuntu 20.04 LTS 中检查它:

file -i teste.xml
/tmp/teste.xml: text/xml; charset=unkNown-8bit

当我使用 gedit 打开它时,强调的 vogal 看起来很好,但欧元符号却没有(从 128 到 159 的所有字符都被弄乱了)。

我检查了 Windows 10 虚拟机,一切顺利。在 Windows 和 Linux 网络浏览器中,它也显示一切正常。

那么,是文件命令的问题吗?如何在 Linux 中检查文件的正确字符?

谢谢

编辑 结果文件可以得到here

第二次编辑 我发现了一个错误代码行:

    r.header('Content-Type','text/xml; charset=iso8859-1');

必须是:

r.header('Content-Type','text/xml; charset=Windows-1252');

解决方法

了解字符编码是什么和不是什么很重要。

文本文件实际上只是一个比特流;或者,因为我们大多同意一个字节中有 8 位,一个字节流。字符编码是一个查找表(有时是更复杂的算法),用于决定向人类显示该字节流的哪些字符。

例如,在 Windows-1252 中编码的字符“€”是位串 10000000。相同的位串在其他编码中意味着其他东西 - 大多数编码为所有 256 个可能的字节分配 some 含义。

如果某个软件知道该文件应该被读取为 Windows-1252,它可以查找该编码的映射并显示“€”。这就是浏览器显示正确内容的方式:您已在 Content-Type 标头中告诉它们使用 Windows-1252 查找表。

将文件保存到磁盘后,来自 Content-Type 标头的“Windows-1252”标签不会存储在任何地方。因此,查看该文件的任何程序都可以看到它包含位字符串 10000000,但它不知道要在哪个映射表中查找。您在 HTTP 标头中所做的任何事情都不会改变这一点 - 没有其中一些将影响它在磁盘上的保存方式。

在这种特殊情况下,“文件”命令可以查看 XML 文档内部的“编码”标记,并在那里找到“windows-1252”。我的猜测是它根本没有那个功能。因此,它使用它的通用逻辑来猜测编码:它可能与 ASCII 兼容,因为它以 ASCII 中拼写 <?xml 的字节开头;但它不是 ASCII 本身,因为它有 0000000001111111 范围之外的字节;除此之外的任何东西都很难猜测,所以输出“unknown-8bit”。