【问题标题】:Why is my Javascript view on a buffer all zeroes?为什么我在缓冲区上的 Javascript 视图全为零?
【发布时间】:2019-02-28 12:07:13
【问题描述】:

我创建了一个缓冲区,然后在其上创建了一个 Uint8Array,但该数组没有任何值。我希望它具有缓冲区的值。这是一个易于重现的示例:

var buf = new ArrayBuffer(32);
for (var index = 0; index < 32; index++) buf[index] = index;
console.log(buf);
var arr = new Uint8Array(buf);
console.log(arr);

我在现实中尝试的是这样的日期格式转换器:

//Buffers and views
function convertDateTimeToFormat(date, initialFormat, endFormat) {
    var buf = new ArrayBuffer(14);
    var result = new Uint8Array(buf);
    console.log(date);
    var initialPositions = {};
    var endPositions = {};
    var sizeSoFar = 0;
    for (var c of initialFormat) {
        if (c === 'y') {
            initialPositions.y = new Uint32Array(date, sizeSoFar, 1);
        } else {
            initialPositions[c] = new Uint8Array(date, sizeSoFar, 2);
        }
        sizeSoFar += ((c === 'y') ? 4 : 2);
    }
    sizeSoFar = 0;
    for (var c of endFormat) {
        if (c === 'y') {
            endPositions.y = new Uint32Array(buf, sizeSoFar, 1);
        } else {
            endPositions[c] = new Uint8Array(buf, sizeSoFar, 2);
        }
        sizeSoFar += ((c === 'y') ? 4 : 2);
    }
    for (var key in initialPositions) {
        var limit = (key === 'y') ? 4 : 2;
        for (var index = 0; index < limit; index++) endPositions[c][index] = initialPositions[c][index];
    }
    return result;
}
//2019-03-01 13:03:50
var buf = new ArrayBuffer( 14 );
buf[0] = 2;
buf[1] = 0;
buf[2] = 1;
buf[3] = 9;
buf[4] = 0;
buf[5] = 3;
buf[6] = 0;
buf[7] = 1;
buf[8] = 1;
buf[9] = 3;
buf[10] = 0;
buf[11] = 3
buf[12] = 5;
buf[13] = 0;
console.log(convertDateTimeToFormat(buf, "yMdHms", "yMdHms"));
console.log(convertDateTimeToFormat(buf, "yMdHms", "MdyHms"));

但是由于我在这个问题开始时描述的行为,结果都是零。

这可行,但并不优雅,因为它需要日期格式,如果我要确保输入与日期格式无关,那么代码将变得非常复杂:

//Buffers and views
var results = {};
var buf = new ArrayBuffer( 4 );
results.uint32 = new Uint32Array(buf);
results.int8 = new Uint8Array(buf);
results.uint8 = new Int8Array(buf);
results.int8[2] = -1;
console.log(results);
results.int8[2] = 0;
results.int8[1] = -1;
console.log(results);
results.int8[1] = 0;
results.int8[0] = -1;
console.log(results);

//Buffers and views
function convertDateTimeToFormat(date, format) {
    var buf = new ArrayBuffer(14);
    var result = new Uint8Array(buf);
    var positions = {
        y: 0,
        M: 4,
        d: 6,
        H: 8,
        m: 10,
        s: 12
    };
    for (var index = 0; index < 14; index++) {
        result[index] = date[positions[format[index]]++];
    }
    return result.join("");
}
var results = {};
//2019-03-01 13:03:50
var buf = new ArrayBuffer( 14 );
buf[0] = 2;
buf[1] = 0;
buf[2] = 1;
buf[3] = 9;
buf[4] = 0;
buf[5] = 3;
buf[6] = 0;
buf[7] = 1;
buf[8] = 1;
buf[9] = 3;
buf[10] = 0;
buf[11] = 3
buf[12] = 5;
buf[13] = 0;
console.log(convertDateTimeToFormat(buf, "yyyyMMddHHmmss"));
console.log(convertDateTimeToFormat(buf, "MMddyyyyHHmmss"));

【问题讨论】:

  • 为什么还要使用缓冲区而不是简单的纯字符串?
  • 在您的第一个示例中,当您console.log(arr.buffer); 时,您会注意到Uint8Array 实际上确实记录了ArrayBuffer
  • 我认为这就像 Bergi 所说的那样,它只是一片内存,而 Uint8Array 只是无法直接访问其内容。我想知道为什么在 mdn 文档中,如果没有复制值,他们允许使用 ArrayBuffer 构造 Uint8Array 。没有多大意义。
  • @kemicofa 这正是我的问题。我知道我可以解决问题,例如从缓冲区读取每个字节并填充我的视图,但我还必须注意字节顺序,这在我看来完全违背了拥有类型化数组的目的.因此,如果有一种解决方案可以从缓冲区中自动填充 Uint 视图,那么如果想要进行微优化,那么使用类型化数组将是有意义的。如果不是,那我根本不明白为什么我们有类型数组。
  • @kemicofa 的“自动”我当然是指语言级别,而不是为其编写算法。

标签: javascript


【解决方案1】:

ArrayBuffer 只是一个代表内存片的对象。它有一个固定的大小,就是这样。它确实 not 具有表示内容的属性,因为您需要一个类型化的数组作为缓冲区上的视图。您的代码只是将属性分配给作为对象工作的缓冲区,但它实际上并没有操纵保持为零的字节内容。

如果您不需要缓冲区,则根本不要显式实例化它。随便写

var arr = new Uint8Array(32);
for (var index = 0; index < 32; index++) arr[index] = index;
console.log(arr.buffer); 
console.log(arr);

在您的实际代码中,您似乎想使用Uint8Array 将数字存储在单个字节中。也许您应该只将该数组而不是底层缓冲区传递给函数。

你可以这样创建它:

const arr = Uint8Array.of(2,0,1,9,0,3,0,1,1,3,0,3,5,0);
// or       Uint8Array.from([2,0,1,9,0,3,0,1,1,3,0,3,5,0])
// or       new Uint8Array(2,0,1,9,0,3,0,1,1,3,0,3,5,0]);
const buf = arr.buffer;

【讨论】:

  • 我同意你的说法,但是为什么 Uint8Array 上的 mdn 文档显示如果内容没有被复制,它可以接受 ArrayBuffer 呢?
  • 实际上,如果我在创建视图后分配数据,它可以工作,但是如果您在我事先不知道日期格式的问题中查看我的其他示例,您会看到我制作的一个实际示例在缓冲区填充数据后,能够定义视图会更好。
  • @kemicofa 它可以接受将成为视图的现有缓冲区。 (我不确定您所说的“被复制”是什么意思)。但它也可以自己创建缓冲区,这通常更简单。
  • @LajosArpad 您可以在填充缓冲区后定义其他视图,没问题。关键是,在最初填充它时,您还需要使用视图。
猜你喜欢
  • 1970-01-01
  • 2018-07-13
  • 2016-11-14
  • 2016-07-20
  • 2016-04-17
  • 2019-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多