使用ASCII编码读取文件

4

文件:

脚本:

require("fs").readFile ("file", "ascii", function (e, d){
    console.log(d==="聵") //true
})

这怎么可能呢?不是ASCII字符,它使用三个字节编码,即0xE881B5。根据预期,我应该得到è\u0081µ,因为ASCII字符只使用一个字节进行编码。如果我使用“binary”编码读取,则输出true,而如果使用ASCII编码,就会得到我的预期结果……
require("fs").readFile ("file", "binary", function (e, d){
    console.log(d === "è\u0081µ") //true
})

这个结果是有意的吗?如果ASCII编码返回与UTF8编码相同的结果,那么为什么“ascii”是可能的参数?

编辑:

这是内容(使用HxD程序打开):

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

00000000  E8 81 B5                                         è.µ

并且:

require("fs").readFile ("file", function (e, d){
    console.log (d.toString ("ascii") === "聵") //true
    console.log (d.toString ("utf8") === "聵") //true
    console.log (d.toString ("binary") === "è\u0081µ") //true
    console.log (d) //<Buffer e8 81 b5>
})

问题已提交给开发人员:https://github.com/joyent/node/issues/4413

为了清晰起见,还需添加a)文件的十六进制转储和b)变量“d”的长度。 - Deestan
3个回答

3
快速的答案是,无论是ascii还是utf8,Node在从Buffer转换为字符串时不会进行任何魔法。你的utf8字符串完全无效的ascii,所以理想情况下它应该抛出一个错误,但显然它没有。我不会期望出现è\u0081µ,因为那是无效的ascii
你可以在Node源代码中看到,从缓冲区转换为字符串的代码是...slice函数。这些构造函数并没有做什么花哨的事情,它们只是将一系列字节转换成JS字符串,假设它在该编码中是有效的。
这两种编码之间的差异来自于该文件中的AsciiWrite和Utf8Write函数,它们以不同的方式处理事物。
例如:
new Buffer("聵", 'ascii') // <Buffer 75>
new Buffer("聵", 'utf8')  // <Buffer e8 81 b5>

正如您从测试中看到的那样,binary 更符合您所寻找的内容。 binary 遍历缓冲区中的每个单独字节,并返回一个字符串,其中每个代码点都具有该字节值。
(new Buffer([0xe8, 0x81, 0xb5])).toString('binary').charCodeAt(0); // 0xe8

那很有道理。如果文件是有效的ASCII格式,就可以像UTF-8一样读取它。Node只是不进行任何验证。 - Deestan

0

-1

我不确定那是什么语言,但我猜测是日语(如果我错了请纠正我)。但我相信你提供的字符恰好符合ASCII标准,这只是巧合,日语字符编码

然而,Shift JIS 有一个不幸的特性,它经常会破坏任何没有专门设计来处理它的解析器(读取编码文本的软件)。例如,如果文本搜索方法没有为 Shift JIS 设计,则可能会出现误报。另一方面,EUC 在已经为 7 位 ASCII 编写的解析器中处理得更好(因此在 UNIX 上使用 EUC 编码,其中大部分文件处理代码历史上仅针对英语编码编写)。但是,EUC 与第一个主要日语编码 JIS X 0201 不兼容。进一步的复杂性是由于最初的互联网电子邮件标准仅支持 7 位传输协议。因此,JIS 编码被开发用于发送和接收电子邮件。
在像 JIS 这样的字符集标准中,并非所有所需字符都包含在内,因此有时会使用外字("external characters")来补充字符集。外字可以采用外部字体包的形式,其中普通字符已被替换为新字符,或者新字符已添加到未使用的字符位置。但是,在互联网环境中,外字并不实用,因为必须将字体集与文本一起传输才能使用外字。因此,这些字符用类似或更简单的字符代替,或者可能需要使用支持所需字符的更大字符集(如 Unicode)来编写文本。

我建议你尝试一些更“奇特”的字符,因为你的测试可能会失败。


@Deestan 在你的原始问题中哪里提到了utf8?除非我漏看了什么,二进制等于utf8吗? - Woot4Moo
我已经选取了一个随机的Unicode字符,但我不知道它属于哪种语言。如果我使用另一个字符,比如Ж,那么这个字符将被编码为2个字节,但是如果我使用ASCII编码并执行d === "Ж",则会输出true。 - Gabriel Llamas
该文件采用UTF8编码。0xE881B5是“聪”字的UTF8编码,也是存储在文件中的内容。以UTF8格式读取应该得到“聪”字。以二进制格式读取应该得到“\u00e8\u0081\u00b5”。以ASCII格式读取将会出现错误。 - Deestan
@Deestan 如果node.js将其转换为&#1046;并在后端进行一些魔法处理,则以ASCII格式阅读它不会引发错误。 - Woot4Moo
如果节点忽略了我的编码参数并执行了“某些魔法”,那么显然它不会像应该的那样报错。 - Deestan
显示剩余2条评论

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