我想以big endian格式将64位(8字节)大整数存储到nodejs缓冲区对象。
关于此任务的问题是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位整数并在读取时找到丢失的510。有人会介意为这两个问题展示解决方案吗?
答案 0 :(得分:9)
我认为你在寻找的是:
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
答案 1 :(得分:2)
我很困惑,因为0xFFFF
的示例值仅为16位,而不是64位。
请记住,JS number
类型被指定为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
当适当的值为18446744073709552000
时,结果为18446744073709551615
。
var bignum = require('bignum');
var b = new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
var val = bignum.fromBuffer(b);
这会生成BigNum
对象,其值为18446744073709551615
。
另外,为了详细说明您的示例代码,您使用的值仅为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);
答案 2 :(得分:1)
读取和写入最多Number.MAX_SAFE_INTEGER
的UINT编号。
这仅在node.js中有效,不能在浏览器端移植。
function uintToBase62(n) {
if (n < 0) throw 'unsupported negative integer';
let uintBuffer;
if (n < 0x7FFFFFFF) {
uintBuffer = new Buffer(4);
uintBuffer.writeUInt32BE(n, 0);
} else {
// `~~` double bitwise operator
// The most practical way of utilizing the power of this operator is to use it as a replacement
// for Math.floor() function as double bitwise NOT performs the same operation a lot quicker.
// You can use it, to convert any floating point number to a integer without performance overkill
// that comes with Math.floor(). Additionally, when you care about minification of your code,
// you end up using 2 characters (2 tildes) instead of 12.
// http://rocha.la/JavaScript-bitwise-operators-in-practice
const big = ~~(n / 0x0100000000);
const low = (n % 0x0100000000);
uintBuffer = new Buffer(8);
uintBuffer.writeUInt32BE(big, 0);
uintBuffer.writeUInt32BE(low, 4);
}
return uintBuffer.toString('hex');
}
进行转换
function uintFromBase62(uintBuffer) {
const n = parseInt(uintBuffer.toString('hex'), 16);
return n;
}
答案 3 :(得分: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);
答案 4 :(得分:0)
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); //
上面的示例使用Number.MAX_SAFE_INTEGER
,Math.pow(2,53)-1
。如果你需要使用更大的数字,它们应该作为bignum字符串访问...如果你可以保持在JS中的整数范围内,你可以保留它们并按上述方式进行转换。
答案 5 :(得分:0)
读取/写入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
我使用此代码时没有任何特殊模块。
<强>更新强>
仅适用于数字<= Number.MAX_SAFE_INTEGER