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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14963182/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 23:02:10  来源:igfitidea点击:

How to convert last 4 bytes in an array to an integer?

javascriptintegerbytearraybitconverter

提问by Joey Morani

If I have an Uint8Arrayarray in JavaScript, how would I get the last four bytes and then convert that to an int? Using C# I would do something like this:

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

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

Is there an inequivalent way to do this using JavaScript?

有没有一种不等价的方式使用 JavaScript 来做到这一点?

回答by Francis Avila

Access the underlying ArrayBufferand create a new TypedArraywith a slice of its bytes:

访问底层ArrayBufferTypedArray使用其字节切片创建一个新的:

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];

If the TypedArraydoes not cover the entire buffer, you need to be a little trickier, but not much:

如果TypedArray没有覆盖整个缓冲区,则需要稍微棘手一些,但不多:

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

This works in both cases.

这在两种情况下都有效。

If the bytes you want fit in the alignment boundary of your underlying buffer for the datatype (e.g., you want the 32-bit value of bytes 4-8 of the underlying buffer), you can avoid copying the bytes with slice()and just supply a byteoffset to the view constructor, as in @Bergi's answer.

如果您想要的字节适合数据类型的底层缓冲区的对齐边界(例如,您想要底层缓冲区的字节 4-8 的 32 位值),则可以避免复制字节,slice()只需提供一个字节偏移量到视图构造函数,如@Bergi 的回答。

Below is a very-lightly-tested function that should get the scalar value of any offset you want. It will avoid copying if possible.

下面是一个经过非常轻松测试的函数,它应该可以获取您想要的任何偏移量的标量值。如果可能,它将避免复制。

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]
    }
}

You would use it like this:

你会像这样使用它:

// positive or negative byte offset
// relative to beginning or end *of a view*
100992003 === scalarValueAs(u8, -4, Uint32Array)
// positive or negative byte offset
// relative to the beginning or end *of a buffer*
100992003 === scalarValue(u8.buffer, -4, Uint32Array)

回答by lmortenson

Do you have an example? I think this would do it:

你有例子吗?我认为这会做到:

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

回答by jerry

A little inelegant, but if you can do it manually based on the 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];
}

This can be extended to other data lengths

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

Edit: Thanks to David for pointing out my typos

编辑:感谢大卫指出我的错别字

回答by yms

Nowadays if you can live with IE 11+ / Chrome 49+ / Firefox 50+, then you can use DataViewto make your life almost as easy as in C#:

现在,如果您可以使用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());

Test it here: https://jsfiddle.net/3udtek18/1/

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

回答by Bergi

It should be more efficient to just create an Uint32Arrayviewon the same ArrayBuffer and accessing the 32-bit number directly:

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

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];

回答by cIph3r

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);

回答by Pawe? Audionysos

It's a shame there are not build in ways to do this. I needed to read variables of variable sizes so based on Imortenson answer I've wrote this little function where pis read position and sis number of bytes to read:

很遗憾没有构建方法来做到这一点。我需要读取可变大小的变量,因此根据 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);