【问题标题】:zlib implementation difference between nodejs [13.13.0] and ruby [2.5.1p57]nodejs [13.13.0] 和 ruby​​ [2.5.1p57] 之间的 zlib 实现差异
【发布时间】:2020-05-07 01:57:39
【问题描述】:

我正在学习 git 的内部结构,这是我存储库中的一棵树:

git cat-file 88e38705fdbd3608cddbe904b67c731f3234c45b -p
100644 blob ce013625030ba8dba906f756967f9e9ca394464a    hello.txt
100644 blob cc628ccd10742baea8241c5924df992b5c019f71    world.txt

当我使用 Ruby 的 zlib 时:

puts Zlib::Inflate.inflate(STDIN.read)

并使用hexdump -C 管道输出:

cat .git/objects/88/e38705fdbd3608cddbe904b67c731f3234c45b | rinflate | hexdump -C

这是输出:

00000000  74 72 65 65 20 37 34 00  31 30 30 36 34 34 20 68  |tree 74.100644 h|
00000010  65 6c 6c 6f 2e 74 78 74  00 ce 01 36 25 03 0b a8  |ello.txt...6%...|
00000020  db a9 06 f7 56 96 7f 9e  9c a3 94 46 4a 31 30 30  |....V......FJ100|
00000030  36 34 34 20 77 6f 72 6c  64 2e 74 78 74 00 cc 62  |644 world.txt..b|
00000040  8c cd 10 74 2b ae a8 24  1c 59 24 df 99 2b 5c 01  |...t+..$.Y$..+\.|
00000050  9f 71                                             |.q|
00000052

但是,当我使用 NodeJS 时:

  const zlib = require("zlib");
  const fs = require("fs");
  fs.writeFileSync("/dev/stdout", zlib.inflateSync(fs.readFileSync("/dev/stdin")).toString());

我得到这个输出:

00000000  74 72 65 65 20 37 34 00  31 30 30 36 34 34 20 68  |tree 74.100644 h|
00000010  65 6c 6c 6f 2e 74 78 74  00 ef bf bd 01 36 25 03  |ello.txt.....6%.|
00000020  0b ef bf bd db a9 06 ef  bf bd 56 ef bf bd 7f ef  |..........V.....|
00000030  bf bd ef bf bd ef bf bd  ef bf bd 46 4a 31 30 30  |...........FJ100|
00000040  36 34 34 20 77 6f 72 6c  64 2e 74 78 74 00 ef bf  |644 world.txt...|
00000050  bd 62 ef bf bd ef bf bd  10 74 2b ef bf bd ef bf  |.b.......t+.....|
00000060  bd 24 1c 59 24 df 99 2b  5c 01 ef bf bd 71        |.$.Y$..+\....q|

为什么会有这种差异?我怎样才能让 NodeJS 和 Ruby 输出相同的东西?

【问题讨论】:

  • 看起来节点正在尝试将数据解释为 UTF-8 并添加 unicode 替换字符(在 UTF-8 中具有字节 EF BF BD)。使用 .toString('binary') 而不是普通的 .toString() 是否有效?
  • @matt,感谢您的建议。我用 toString() 尝试了不同的编码,没有任何效果。所以我完全删除了 toString() 并且它起作用了!现在 Ruby 和 NodeJS 版本的输出是相同的,虽然我不知道为什么..

标签: node.js ruby git zlib


【解决方案1】:

在 JavaScript 中,字符串是以 UTF-16 编码的 Unicode 字符序列。您不能将非文本内容存储在 JavaScript 字符串中,因为它不提供以任何其他编码方式存储的方法。

但是,Git 树对象是二进制的,并且包含二进制格式(通常是 SHA-1)的加密哈希,因此它们不会包含文本内容,也不能存储在 JavaScript 字符串中。无论如何,如果您尝试这样做,您将获得被 U+FFFD 替换的无效字节值,替换字符在 UTF-8 中编码为 0xef 0xbf 0xbd,从而破坏数据。

如果您不调用toString(),您的数据将存储在某种二进制缓冲区对象中,并且具有 zlib 解码的字节。

另一方面,Ruby 对每个字符串都有一个编码,并且可以使用编码ASCII-8BIT(也称为BINARY)存储二进制字符串。因此,如果您有 Ruby 代码,这可能就可以正常工作。

【讨论】:

  • 谢谢,但我可以像这样更改字符串的编码:Buffer.toString('binary'),那么这是否会将字符串更改为 UTF-16,然后再更改为二进制?
  • binary 不会阻止它被编码为 UTF-16,它只是将字节解释为 Latin-1 (ISO 8859-1)。您的字符串仍将是 UTF-16,它可能会或可能不会提供正确的结果。不要将字符串用于非文本数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 2019-03-22
相关资源
最近更新 更多