在某些情况下,将 nodejs 缓冲区转换为字符串并返回缓冲区会产生不同的结果

Converting a nodejs buffer to string and back to buffer gives a different result in some cases

我创建了一个 .docx 文件。 现在,我这样做:

// read the file to a buffer
const data = await fs.promises.readFile('<pathToMy.docx>')

// Converts the buffer to a string using 'utf8' but we could use any encoding
const stringContent = data.toString()

// Converts the string back to a buffer using the same encoding
const newData = Buffer.from(stringContent)

// We expect the values to be equal...
console.log(data.equals(newData)) // -> false

我不明白在哪个过程中字节被改变了...

我已经花了很多时间试图解决这个问题,但没有任何结果......如果有人能帮助我理解我遗漏了什么部分,那就太棒了!

一个 .docX 文件不是 UTF-8 字符串(它是一个二进制 ZIP 文件)所以当你将它读入一个 Buffer 对象然后调用 .toString() 时,你假设它已经在缓冲区中编码为 UTF-8,您现在想将其移动到 Javascript 字符串中。那不是你所拥有的。您的二进制数据可能会遇到在 UTF-8 中无效的内容,这些内容将被丢弃或强制转换为有效的 UTF-8,从而导致不可逆转的更改。

Buffer.toString() 所做的是获取一个已经用 UTF-8 编码的缓冲区,并将其放入 Javascript 字符串中。请参阅 the doc

中的此评论

如果编码是'utf8'并且输入中的字节序列不是有效的UTF-8,那么每个无效字节都被替换为替换字符U+FFFD .

因此,您在问题中显示的代码错误地假设 Buffer.toString() 采用二进制数据并将其可逆编码为 UTF8 字符串。这不是它的作用,这就是为什么它没有达到您的预期。

你的问题没有描述你实际想要完成的事情。如果您想对 .docX 文件做一些有用的事情,您可能需要实际将其从二进制 ZIP 文件格式解析为文件的适当格式的实际组件。

既然您解释了您正在尝试将其存储在 localStorage 中,那么您需要将二进制文件编码为字符串格式。一种流行的选择是 Base64,虽然它不是超级高效(在大小方面),但它比许多其他选择要好。有关此主题的先前讨论,请参阅 Binary Data in JSON String. Something better than Base64。忽略其他答案中关于压缩的注释,因为您的数据已经是 ZIP 压缩的。

我实际上可以通过使用来解决我的问题:

data.toString('binary') 然后 Buffer.from(stringContent, 'binary')

这实际上是我(错误地)期望的默认行为。