Node.js支持的编码列表

186

我需要读取一个使用ISO-8859-1(也称为Latin1)编码的文件,就像这样:

var file_contents = fs.readFileSync("test_data.html", "latin1");

然而,Node会抱怨"latin1"或"ISO-8859-1"不是有效的编码("Error: Unknown encoding")。

readFileSync接受哪些编码?


我不知道将源文件转换为utf8是否可行。如果可以,这里是一个链接。https://superuser.com/questions/762473/ansi-to-utf-8-in-notepad - mathheadinclouds
4个回答

287

Node原生支持的编码格式list of encodings相当有限:

  • ascii
  • base64
  • base64url (Node v14+)
  • hex
  • ucs2/ucs-2/utf16le/utf-16le
  • utf8/utf-8
  • binary/latin1 (ISO8859-1,在node 6.4.0+版本中仅支持latin1)

如果您使用的是旧版本低于6.4.0,或者不想处理非Unicode编码,您可以重新编码字符串:

使用iconv-lite重新编码文件:

var iconvlite = require('iconv-lite');
var fs = require('fs');

function readFileSync_encoding(filename, encoding) {
    var content = fs.readFileSync(filename);
    return iconvlite.decode(content, encoding);
}

或者使用iconv

var Iconv = require('iconv').Iconv;
var fs = require('fs');

function readFileSync_encoding(filename, encoding) {
    var content = fs.readFileSync(filename);
    var iconv = new Iconv(encoding, 'UTF-8');
    var buffer = iconv.convert(content);
    return buffer.toString('utf8');
}

2
对于那些编译iconv遇到问题的人,我推荐使用iconv-lite。它不需要编译,并且据开发者说比iconv更快,被像Grunt、Nodemailer、Yeoman这样的流行工具所使用。 - Telémako
4
你在回答中说的 -- ISO-8859-1 (又称为 latin1) 不被支持 -- 在 Node v8.1.4 中并不是这样的。可以查看 此文档页面,查看 Buffer 支持的所有编码,其中包括 latin1 (其别名为 binary)。 - nbkhope
1
我发现很奇怪的是,根据 https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings ,编码名称'latin1'和'binary'意思相同。为什么会这样呢?我因为假设‘binary’会和“无编码”一样,而被咬了一口。 - Panu Logic
2
@PanuLogic 当你从字节字符串转换为字符字符串时,你需要_一些_编码。latin1是可逆的——即使你的输入是一个mp4视频文件,该字符串也将是有效的(虽然没有意义),并且转换回字节将产生原始字节。对于二进制数据,请使用Buffer/Uint8Array - phihag
1
@PanuLogic 如果您在不指定编码的情况下编写字符串,则字符串将被编写为UTF-8。因此,如果没有编码就读取并编写为latin1是不安全的;这将创建乱码。相反,请使用{encoding: null}(或不指定编码)进行读取。这样,您将获得一个缓冲区。缓冲区已经是二进制数据,因此在写入时忽略encoding参数。 - phihag
显示剩余9条评论

18

缓冲区文档中详细列出了各种编码方式。

缓冲区和字符编码:

字符编码

  • utf8: 多字节编码的Unicode字符。许多网页和其他文档格式都使用UTF-8。这是默认的字符编码。
  • utf16le: 多字节编码的Unicode字符。与utf8不同,字符串中的每个字符将使用2或4个字节进行编码。
  • latin1: Latin-1代表ISO-8859-1。此字符编码仅支持Unicode字符从U+0000U+00FF

二进制到文本编码

  • base64: Base64编码。从字符串创建缓冲区时,此编码还将正确接受RFC 4648第5节中指定的“URL和文件名安全字母表”。
  • base64url (Node v14+):Base64 URL编码,如RFC 4648第5节中所述。从字符串创建缓冲区时,此编码还将正确接受常规的Base64编码字符串。将缓冲区编码为字符串时,此编码将省略填充。
  • hex: 将每个字节编码为两个十六进制字符。
  • 传统字符编码

    • ascii: 仅适用于7位ASCII数据。一般来说,在对ASCII文本进行编码或解码时,使用'utf8'(或者如果数据总是只包含ASCII,则使用'latin1')将是更好的选择。
    • binary: 'latin1'的别名。
    • ucs2: 'utf16le'的别名。

    2

    从v12开始,Node支持以下编码值:

    • ascii
    • base64
    • hex
    • latin1
    • ucs2
    • utf16le
    • utf8

    Node v14及更高版本添加了base64url编码。

    使用此shell脚本从每个Node版本中提取支持的编码:

    for v in {12..19}; do echo v$v; curl -L https://raw.githubusercontent.com/nodejs/node/v$v.x/lib/buffer.js --silent | grep -A 100000 'const encodingOps' | grep -B 100000 -E '^}' -m 1 | grep -Eo '^  [^ :}]+' | grep -Eo '[^ ]+' | sort; echo ---; done
    

    0
    如果上述解决方案对您无效,可能可以通过以下纯Node.js代码获得相同的结果。在我的OSX上运行“npm install iconv”时,上述方法对我无效并导致编译异常:
    npm install iconv
    
    npm WARN package.json portalServer@0.1.0 No README.md file found!
    npm http GET https://registry.npmjs.org/iconv
    npm http 200 https://registry.npmjs.org/iconv
    npm http GET https://registry.npmjs.org/iconv/-/iconv-2.0.4.tgz
    npm http 200 https://registry.npmjs.org/iconv/-/iconv-2.0.4.tgz
    
    > iconv@2.0.4 install /Users/markboyd/git/portal/app/node_modules/iconv
    > node-gyp rebuild
    
    gyp http GET http://nodejs.org/dist/v0.10.1/node-v0.10.1.tar.gz
    gyp http 200 http://nodejs.org/dist/v0.10.1/node-v0.10.1.tar.gz
    xcode-select: Error: No Xcode is selected. Use xcode-select -switch <path-to-xcode>, or see the xcode-select manpage (man xcode-select) for further information.
    

    如果没有指定编码,fs.readFileSync()将返回一个Buffer。而Buffer有一个toString()方法,如果没有指定编码,它将转换为UTF8,从而给出文件的内容。请参阅nodejs文档。这对我很有效。


    2
    问题在于如果没有指定,Buffer会假设数据已经是utf8编码,而不会尝试从latin1转换为utf8。 - bluesmoon

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