如何将数组中的最后4个字节转换为整数?

时间:2013-02-19 17:01:59

标签: javascript integer bytearray bitconverter

如果我在JavaScript中有一个Uint8Array数组,我如何获得最后四个字节然后将其转换为int?使用C#我会做这样的事情:

int count = BitConverter.ToInt32(array, array.Length - 4);

是否有使用JavaScript的不等效方法?

8 个答案:

答案 0 :(得分:8)

访问基础ArrayBuffer并使用其字节切片创建新的TypedArray

var u8 = new Uint8Array([1,2,3,4,5,6]); // original array
var u32bytes = u8.buffer.slice(-4); // last four bytes as a new `ArrayBuffer`
var uint = new Uint32Array(u32bytes)[0];

如果TypedArray没有覆盖整个缓冲区,那么你需要更加棘手,但并不多:

var startbyte = u8.byteOffset + u8.byteLength - Uint32Array.BYTES_PER_ELEMENT;
var u32bytes = u8.buffer.slice(startbyte, startbyte + Uint32Array.BYTES_PER_ELEMENT);

这适用于两种情况。

如果您想要的字节适合数据类型的底层缓冲区的对齐边界(例如,您需要底层缓冲区的字节4-8的32位值),则可以避免使用{{复制字节1}}并且只为视图构造函数提供一个byteoffset,就像@ Bergi的回答一样。

下面是一个非常轻微测试的函数,它应该得到你想要的任何偏移量的标量值。如果可能,它将避免复制。

slice()

您可以这样使用它:

function InvalidArgument(msg) {
    this.message = msg | null;
}

function scalarValue(buf_or_view, byteOffset, type) {
    var buffer, bufslice, view, sliceLength = type.BYTES_PER_ELEMENT;
    if (buf_or_view instanceof ArrayBuffer) {
        buffer = buf_or_view;
        if (byteOffset < 0) {
            byteOffset = buffer.byteLength - byteOffset;
        }
    } else if (buf_or_view.buffer instanceof ArrayBuffer) {
        view = buf_or_view;
        buffer = view.buffer;
        if (byteOffset < 0) {
            byteOffset = view.byteOffset + view.byteLength + byteOffset;
        } else {
            byteOffset = view.byteOffset + byteOffset;
        }
        return scalarValue(buffer, view.byteOffset + byteOffset, type);
    } else {
        throw new InvalidArgument('buf_or_view must be ArrayBuffer or have a .buffer property');
    }
    // assert buffer instanceof ArrayBuffer
    // assert byteOffset > 0
    // assert byteOffset relative to entire buffer
    try {
        // try in-place first
        // only works if byteOffset % slicelength === 0
        return (new type(buffer, byteOffset, 1))[0]
    } catch (e) {
        // if this doesn't work, we need to copy the bytes (slice them out)
        bufslice = buffer.slice(byteOffset, byteOffset + sliceLength);
        return (new type(bufslice, 0, 1))[0]
    }
}

答案 1 :(得分:6)

你有一个例子吗?我想这会做到这一点:

var result = ((array[array.length - 1]) | 
              (array[array.length - 2] << 8) | 
              (array[array.length - 3] << 16) | 
              (array[array.length - 4] << 24));

答案 2 :(得分:3)

有点不优雅,但如果你可以根据endianess手动完成。

Little endian:

var count = 0;
// assuming the array has at least four elements
for(var i = array.length - 1; i >= array.length - 4; i--)
{
    count = count << 8 + array[i];
}

Big endian:

var count = 0;
// assuming the array has at least four elements
for(var i = array.length - 4; i <= array.length - 1 ; i++)
{
    count = count << 8 + array[i];
}

这可以扩展到其他数据长度

编辑:感谢大卫指出我的拼写错误

答案 3 :(得分:1)

在同一个ArrayBuffer上创建Uint32Array view并直接访问32位数字应该更有效:

var uint8array = new Uint8Array([1,2,3,4,5,6,7,8]);
var uint32array = new Uint32Array(
                    uint8array.buffer,
                    uint8array.byteOffset + uint8array.byteLength - 4,
                    1 // 4Bytes long
                  );
return uint32array[0];

答案 4 :(得分:1)

如果你可以和IE 11+ / Chrome 49+ / Firefox 50+一起生活,那么你可以使用DataView让你的生活几乎和C#一样简单:

var u8array = new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]); // -1
var view = new DataView(u8array.buffer)
console.log("result:" + view.getInt32());

在此测试:https://jsfiddle.net/3udtek18/1/

答案 5 :(得分:1)

令我惊讶的是,其他答案没有使用本机 Buffer 对象,它在一个简单的本机库中提供了很多此类工具。这个库可能没有被广泛用于位打包/解包,仅仅是因为人们不认为在这里检查,我也花了一段时间才找到它,但它是在 nodejs/javascript/ 中进行位打包/解包的正确工具/打字稿。

你可以这样使用它:

// Create a simple array with 5 elements. We'll pop the last 4 and you should expect the end value to be 1 because this is a little-endian array with all zeros other than the 1 in the littlest(?)-endian
const array = [0, 1, 0, 0, 0]

// get the last 4 elements of your array and convert it to a Buffer
const buffer = Buffer.from(array.slice(-4));

// Use the native Buffer type to read the object as an (U) unsigned (LE) little-endian 32 (32 bits) integer
const value = Buffer.readUInt32LE();

或者,更简洁:

const value = Buffer.from(array.slice(-4)).readUInt32LE();

答案 6 :(得分:0)

var a = Uint8Array(6)
a.set([1,2,8,0,0,1])

 i1 = a[a.length-4];
 i2 = a[a.length-3];
 i3 = a[a.length-2];
 i4 = a[a.length-1];

console.log(i1<<24 | i2<<16 | i3<<8 | i4);

答案 7 :(得分:0)

可惜的是没有办法做到这一点。 我需要读取可变大小的变量,因此基于Imortenson的回答,我编写了这个小函数,其中p是读取位置,s是要读取的字节数:

function readUInt(arr, p, s) {
    var r = 0;
    for (var i = s-1; i >= 0; i--) {
        r |= arr[p + i] << (i * 8);
    } return r >>> 0;
} 

var iable = readUint(arr, arr.length - 4, 4);