nodejs将64位无符号整数写入缓冲区

我想以64字节(8字节)的大整数存储一个nodejs缓冲区对象的big endian格式。

关于这个任务的问题是nodejs缓冲区只支持最大写32位整数(使用buf.write32UInt32BE(value,offset))。 所以我虽然为什么不能把64位整数分开?

var buf = new Buffer(8); buf.fill(0) // clear all bytes of the buffer console.log(buf); // outputs <Buffer 00 00 00 00 00 00 00 00> var int = 0xffff; // as dezimal: 65535 buf.write32UInt32BE(0xff, 4); // right the first part of the int console.log(buf); // outputs <Buffer 00 00 00 00 00 00 00 ff> buf.write32UInt32BE(0xff, 0); // right the second part of the int console.log(buf); // outputs <Buffer 00 00 00 ff 00 00 00 ff> var bufInt = buf.read32UInt32BE(0) * buf.read32UInt32BE(4); console.log(bufInt); // outputs 65025 

正如你所见,这近乎成功。 问题是分裂64位整数,并find丢失510阅读它。 有人会介意解决这两个问题吗?

我想你正在寻找的是:

 var bufInt = (buf.readUInt32BE(0) << 8) + buf.readUInt32BE(4); 

将第一个数字移位8位,并添加(而不是相乘),返回65535


编辑

另一种写法是:

 var buf = new Buffer(8); buf.fill(0); var i = 0xCDEF; // 52719 in decimal buf.writeUInt32BE(i >> 8, 0); //write the high order bits (shifted over) buf.writeUInt32BE(i & 0x00ff, 4); //write the low order bits console.log(buf); //displays: <Buffer 00 00 00 cd 00 00 00 ef> var bufInt = (buf.readUInt32BE(0) << 8) + buf.readUInt32BE(4); console.log(bufInt); //displays: 52719 

读/写64位值:

 const int64 = Date.now() // 1456909977176 (00 00 01 53 36 9a 06 58) const b = new Buffer(8) const MAX_UINT32 = 0xFFFFFFFF // write const big = ~~(int64 / MAX_UINT32) const low = (int64 % MAX_UINT32) - big b.writeUInt32BE(big, 0) // 00 00 01 53 00 00 00 00 b.writeUInt32BE(low, 4) // 00 00 01 53 36 9a 06 58 // read var time = parseInt(b.toString('hex'), 16) time == int64 // true 

我使用这个代码没有任何特殊的模块。

UPDATE

仅适用于数字<= Number.MAX_SAFE_INTEGER

我很困惑,因为你的示例值0xFFFF只有16位而不是64位。

请记住,JS numbertypes被指定为IEEE754浮点值,因此不能保证能够保存64位无符号值。 如果你想要真正的64位整数支持,你需要使用一个模块来提供它,比如bignum 。 该自述文件具有读取和写入缓冲区值的示例。

浮点值只能表示高达2^53 - 1值,而不会损失精度。 你可以看到在这个例子中使用标准的JS数字:

 var b = new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) var firstHalf = b.readUInt32BE(0); // 4294967295 var secondHalf = b.readUInt32BE(4); // 4294967295 var val = firstHalf * 0x100000000 + secondHalf; // 18446744073709552000 

当适当的值是18446744073709551615时,结果是18446744073709551615

 var bignum = require('bignum'); var b = new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) var val = bignum.fromBuffer(b); 

这会导致一个值为18446744073709551615BigNum对象。

另外,为了详细说明您的示例代码,您使用的值仅为16位,而您正尝试使用32位函数来处理它。 你可以这样做:

 var buf = new Buffer(2); buf.fill(0) // clear all bytes of the buffer console.log(buf); // outputs <Buffer 00 00> var int = 0xffff; // as decimal: 65535 // Write it with a standard 16-bit function calls. buf.writeUInt16BE(int); // OR write it with 2 8-bit function calls. buf.writeUInt8(int & 0xff, 0); // right the first part of the int buf.writeUInt8((int >> 8) & 0xFF, 1); // right the second part of the int console.log(buf); // outputs <Buffer ff ff> // Read it as a 16-bit value. var bufInt = buf.readUInt16BE(0); console.log(bufInt); // OR read it as two 8-bit values. var bufInt = (buf.readUInt8(1) << 8) + buf.readUInt8(0); 
 // sending time var sending_time = new Date().getTime(); buffer.writeInt32LE(parseInt(sending_time & 0xffffffff, 10), 16); buffer.writeInt32LE(parseInt(sending_time / 0xffffffff, 10), 20); 

JavaScript / EcmaScript中的按位操作会强制将数字(或任何值)强制为32位整数。

如果您需要某些精度,或者处理大于32位值的缓冲区,则确实需要使用bignum来获取更大的值。

 var bignum = require('bignum'); //max safe integer to big number var num = bignum(Number.MAX_SAFE_INTEGER.toString()); var buf = num.toBuffer({endian:'big',size:8 /*8-byte / 64-bit*/}); console.log(buf); // 

上面的例子使用Math.pow(2,53)-1 。 如果你需要使用更大的数字,他们应该作为bignumstring访问…如果你可以保持在整数范围内的JS,你可以保留它们,并按照上述转换。