nodejs [13.13.0] 和 ruby [2.5.1p57] 之间的 zlib 实现差异
zlib implementation difference between nodejs [13.13.0] and ruby [2.5.1p57]
我正在学习 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 输出相同的东西?
在 JavaScript 中,字符串是以 UTF-16 编码的 Unicode 字符序列。您不能在 JavaScript 字符串中存储非文本内容,因为它不提供以任何其他编码存储的方法。
但是,Git 树对象是二进制的并且包含二进制格式的加密散列(通常是 SHA-1),因此它们不会有文本内容并且不能存储在 JavaScript 字符串。无论如何,如果您尝试这样做,您将得到替换为 U+FFFD 的无效字节值,替换字符在 UTF-8 中编码为 0xef 0xbf 0xbd,从而破坏数据。
如果您不调用 toString()
,您的数据将存储在某种二进制缓冲区对象中,并且具有 zlib 解码的字节。
另一方面,Ruby 对每个字符串都有一个编码,可以存储编码为 ASCII-8BIT
(也称为 BINARY
)的二进制字符串。所以如果你有 Ruby 代码,这可能会工作得很好。
我正在学习 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 输出相同的东西?
在 JavaScript 中,字符串是以 UTF-16 编码的 Unicode 字符序列。您不能在 JavaScript 字符串中存储非文本内容,因为它不提供以任何其他编码存储的方法。
但是,Git 树对象是二进制的并且包含二进制格式的加密散列(通常是 SHA-1),因此它们不会有文本内容并且不能存储在 JavaScript 字符串。无论如何,如果您尝试这样做,您将得到替换为 U+FFFD 的无效字节值,替换字符在 UTF-8 中编码为 0xef 0xbf 0xbd,从而破坏数据。
如果您不调用 toString()
,您的数据将存储在某种二进制缓冲区对象中,并且具有 zlib 解码的字节。
Ruby 对每个字符串都有一个编码,可以存储编码为 ASCII-8BIT
(也称为 BINARY
)的二进制字符串。所以如果你有 Ruby 代码,这可能会工作得很好。