如何在 Javascript 中存储字节数组

IT技术 javascript arrays html bytearray byte
2021-03-08 14:37:51

我将在 Javascript 中存储大量字节值(很可能超过一百万)。如果我使用带有普通数字的普通数组,则需要 8 MB,因为数字存储为 IEEE 双精度数,但如果我可以将其存储为字节,则只有 1 MB。

我想避免由于显而易见的原因浪费那么多空间。有没有办法将字节存储为字节而不是双精度?浏览器兼容性对我来说不是问题,只要它在 Chrome 中工作即可。这是在 HTML5 中,如果这有区别的话。

4个回答

通过使用类型化数组,您可以存储以下类型的数组

类型 取值范围 大小(字节)
Int8Array -128 到 127 1
Uint8Array 0 到 255 1
Uint8ClampedArray 0 到 255 1
Int16Array -32768 至 32767 2
Uint16Array 0 到 65535 2
Int32Array -2147483648 转 2147483647 4
Uint32Array 0 到 4294967295 4
Float32Array -3.4E38 到 3.4E38 4
Float64Array -1.8E308 到 1.8E308 8
BigInt64Array -2^63 到 2^63 - 1 8
BigUint64Array 0 到 2^64 - 1 8

Stack Snippets 和JSFiddle 中的演示

var array = new Uint8Array(100);
array[42] = 10;
console.log(array[42]);

是的!这将生成 800,000 多个元素的数组的时间从 2.4 秒缩短到 0.12 秒。使用Float32Array会产生惊人的差异!
2021-04-24 14:37:51
我在将 fetch() Promise返回的 Blob 转换为 C# 字节 [] 时遇到问题。你对我应该采取什么方法有什么智慧吗?
2021-05-01 14:37:51
var array = new Uint8Array(100);    
array[10] = 256;
array[10] === 0 // true

我在 Firefox 和 chrome 中进行了验证,它确实是一个字节数组:

var array = new Uint8Array(1024*1024*50);  // allocates 50MBytes
由于array是uint8的数组,256溢出一个字节,使得值等于0
2021-04-21 14:37:51
256 === 0 怎么办?不应该是256吗?
2021-05-02 14:37:51

您可以将数据存储在一些大的固定大小的字符串数组中。访问该字符串数组中的任何特定字符并将该字符视为字节应该是有效的。

看到您想要支持的操作(可能表示为接口)以使问题更加具体,会很有趣。

我想要一个更准确和有用的答案来回答这个问题。这是真正的答案(如果您特别想要一个字节数组,请相应地进行调整;显然,数学运算将偏离8 bits : 1 byte):

class BitArray {
  constructor(bits = 0) {
    this.uints = new Uint32Array(~~(bits / 32));
  }

  getBit(bit) {
    return (this.uints[~~(bit / 32)] & (1 << (bit % 32))) != 0 ? 1 : 0;
  }

  assignBit(bit, value) {
    if (value) {
      this.uints[~~(bit / 32)] |= (1 << (bit % 32));
    } else {
      this.uints[~~(bit / 32)] &= ~(1 << (bit % 32));
    }
  }

  get size() {
    return this.uints.length * 32;
  }

  static bitsToUints(bits) {
    return ~~(bits / 32);
  }
}

用法:

let bits = new BitArray(500);
for (let uint = 0; uint < bits.uints.length; ++uint) {
  bits.uints[uint] = 457345834;
}
for (let bit = 0; bit < 50; ++bit) {
  bits.assignBit(bit, 1);
}
str = '';
for (let bit = bits.size - 1; bit >= 0; --bit) {
  str += bits.getBit(bit);
}
str;

输出:

"00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000101000101100101010
 00011011010000111111111111111111
 11111111111111111111111111111111"

注意:如果这个类是作为全局变量创建的,至少在 Linux 上的 Firefox 76.0 控制台中,这个类在分配位(即每 1000 万次分配约 2 秒)真的很慢......如果另一方面,它被创建为一个变量(即let bits = new BitArray(1e7);),那么它非常(即每 1000 万次分配约 300 毫秒)!


有关更多信息,请参见此处:

请注意,我使用 Uint32Array 是因为无法直接拥有位/字节数组(您可以直接与之交互),并且即使有BigUint64ArrayJS 也仅支持 32 位:

按位运算符将其操作数视为 32 位序列

...

所有按位运算符的操作数都转换为...32 位整数