是否有一种通常被接受的技术,能够有效地将JavaScript字符串转换为ArrayBuffers,反之亦然?具体而言,我希望能够将一个ArrayBuffer的内容写入localStorage
中,并随后读取。
是否有一种通常被接受的技术,能够有效地将JavaScript字符串转换为ArrayBuffers,反之亦然?具体而言,我希望能够将一个ArrayBuffer的内容写入localStorage
中,并随后读取。
ArrayBuffer
-> Buffer
-> String(Base64)
将 ArrayBuffer
转化为 Buffer
,再转化为 Base64 编码的字符串
。
Buffer.from(arrBuffer).toString("base64");
在尝试使用mangini的方法将ArrayBuffer
转换为String
时,我遇到了一些处理大型数组时的问题。具体来说,调用String.fromCharCode.apply(null, new Uint16Array(buf));
会抛出错误:
arguments array passed to Function.prototype.apply is too large
。
为了解决这个问题,我决定分块处理输入的ArrayBuffer
。所以修改后的解决方案是:
function ab2str(buf) {
var str = "";
var ab = new Uint16Array(buf);
var abLen = ab.length;
var CHUNK_SIZE = Math.pow(2, 16);
var offset, len, subab;
for (offset = 0; offset < abLen; offset += CHUNK_SIZE) {
len = Math.min(CHUNK_SIZE, abLen-offset);
subab = ab.subarray(offset, offset+len);
str += String.fromCharCode.apply(null, subab);
}
return str;
}
块大小设置为2^16
,因为这是我在开发环境中发现可行的大小。将值设置得更高会导致相同的错误再次出现。可以通过设置CHUNK_SIZE
变量来改变它的大小。保持偶数非常重要。
关于性能的注意事项 - 我没有对此解决方案进行任何性能测试。然而,由于它基于先前的解决方案,并且可以处理大型数组,我认为没有理由不使用它。
对我来说,这个方法很有效。
static async hash(message) {
const data = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
return hashHex
}
atob()返回的“本地”二进制字符串是一个每个字符1字节的数组。
因此,我们不应该将2字节存储到一个字符中。
var arrayBufferToString = function(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
var stringToArrayBuffer = function(str) {
return (new Uint8Array([].map.call(str,function(x){return x.charCodeAt(0)}))).buffer;
}
BlobBuilder早已被Blob对象所取代。请将Dennis答案中使用BlobBuilder的代码与下面的代码进行比较:
function arrayBufferGen(str, cb) {
var b = new Blob([str]);
var f = new FileReader();
f.onload = function(e) {
cb(e.target.result);
}
f.readAsArrayBuffer(b);
}
var decoder = new TextDecoder ();
var string = decoder.decode (arrayBuffer);
请查看https://developer.mozilla.org/zh-CN/docs/Web/API/TextDecoder/decode
来自emscripten:
function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) {
if (!(maxBytesToWrite > 0)) return 0;
var startIdx = outIdx;
var endIdx = outIdx + maxBytesToWrite - 1;
for (var i = 0; i < str.length; ++i) {
var u = str.charCodeAt(i);
if (u >= 55296 && u <= 57343) {
var u1 = str.charCodeAt(++i);
u = 65536 + ((u & 1023) << 10) | u1 & 1023
}
if (u <= 127) {
if (outIdx >= endIdx) break;
outU8Array[outIdx++] = u
} else if (u <= 2047) {
if (outIdx + 1 >= endIdx) break;
outU8Array[outIdx++] = 192 | u >> 6;
outU8Array[outIdx++] = 128 | u & 63
} else if (u <= 65535) {
if (outIdx + 2 >= endIdx) break;
outU8Array[outIdx++] = 224 | u >> 12;
outU8Array[outIdx++] = 128 | u >> 6 & 63;
outU8Array[outIdx++] = 128 | u & 63
} else {
if (outIdx + 3 >= endIdx) break;
outU8Array[outIdx++] = 240 | u >> 18;
outU8Array[outIdx++] = 128 | u >> 12 & 63;
outU8Array[outIdx++] = 128 | u >> 6 & 63;
outU8Array[outIdx++] = 128 | u & 63
}
}
outU8Array[outIdx] = 0;
return outIdx - startIdx
}
使用方法:
stringToUTF8Array('abs', new Uint8Array(3), 0, 4);
arrbuf = new Uint8Array([104, 101, 108, 108, 111])
text = String.fromCharCode(...arrbuf)
console.log(text)
arrbuf.slice()
。
ArrayBufferView
,可能可以简单地使用括号表示法来复制字符string[i] = buffer[i]
,反之亦然。 - FK82Uint16Array
来处理JS的16位字符),但JavaScript字符串是不可变的,所以您不能直接赋值给一个字符位置。我仍然需要将Uint16Array
中每个值的String.fromCharCode(x)
复制到普通的Array
中,然后在Array
上调用.join()
。 - kpozinstring += String.fromCharCode(buffer[i]);
更加高效。没有内置方法在字符串和类型数组之间转换似乎很奇怪。他们本应该知道会出现这样的情况。翻译:发现大多数现代JavaScript引擎已经将字符串拼接优化到一个程度,在使用“string += String.fromCharCode(buffer[i])”时比其他方式更为便宜。没有内置的方法可以在字符串和类型数组之间进行转换,这似乎有点奇怪,因为他们应该知道这种情况会出现。 - Erin