如何将 ArrayBuffer 转换为 Base64 编码的字符串?

发布于 2025-01-04 19:34:55 字数 64 浏览 6 评论 0原文

我需要一种有效的(读取本机)方法将 ArrayBuffer 转换为需要在多部分帖子上使用的 base64 字符串。

I need an efficient (read native) way to convert an ArrayBuffer to a base64 string which needs to be used on a multipart post.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

淡淡の花香 2025-01-11 19:34:55
function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}

但是,非本机实现速度更快,例如 https://gist.github.com/958841
请参阅http://jsperf.com/encoding-xhr-image-data/6

jsPerf.com 现在是 jsPerf.apphttps://jsperf.app/encoding-xhr-image-data/51

更新基准:https ://jsben.ch/wnaZC

function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}

but, non-native implementations are faster e.g. https://gist.github.com/958841
see http://jsperf.com/encoding-xhr-image-data/6

jsPerf.com is jsPerf.app now: https://jsperf.app/encoding-xhr-image-data/51

Updated benchmarks: https://jsben.ch/wnaZC

雄赳赳气昂昂 2025-01-11 19:34:55

这对我来说效果很好:

var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));

在 ES6 中,语法稍微简单一些:

const base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));

正如注释中指出的,当 ArrayBuffer 很大时,此方法可能会导致某些浏览器中出现运行时错误。无论如何,确切的大小限制取决于实现。

This works fine for me:

var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));

In ES6, the syntax is a little simpler:

const base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));

As pointed out in the comments, this method may result in a runtime error in some browsers when the ArrayBuffer is large. The exact size limit is implementation dependent in any case.

浮生未歇 2025-01-11 19:34:55

对于那些喜欢简短的人,这里有另一个使用 Array.reduce 的方法,它不会导致堆栈溢出:

var base64 = btoa(
  new Uint8Array(arrayBuffer)
    .reduce((data, byte) => data + String.fromCharCode(byte), '')
);

For those who like it short, here's an other one using Array.reduce which will not cause stack overflow:

var base64 = btoa(
  new Uint8Array(arrayBuffer)
    .reduce((data, byte) => data + String.fromCharCode(byte), '')
);
心奴独伤 2025-01-11 19:34:55

OP 没有指定运行环境,但如果您使用 Node.JS,有一个非常简单的方法可以做到这一点。

根据 Node.JS 官方文档:
https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings

// This step is only necessary if you don't already have a Buffer Object
const buffer = Buffer.from(yourArrayBuffer);

const base64String = buffer.toString('base64');

另外,如果您例如,在 Angular 下运行时,Buffer 类也将在浏览器环境中可用。

The OP did not specify the Running Environment, but if you are using Node.JS there is a very simple way to do this.

According to the official Node.JS docs:
https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings

// This step is only necessary if you don't already have a Buffer Object
const buffer = Buffer.from(yourArrayBuffer);

const base64String = buffer.toString('base64');

Also, if you are running under Angular for example, the Buffer class will also be made available in a browser environment.

↙温凉少女 2025-01-11 19:34:55

还有另一种异步方式使用 Blob 和 FileReader。

我没有测试性能。但这是一种不同的思维方式。

function arrayBufferToBase64( buffer, callback ) {
    var blob = new Blob([buffer],{type:'application/octet-binary'});
    var reader = new FileReader();
    reader.onload = function(evt){
        var dataurl = evt.target.result;
        callback(dataurl.substr(dataurl.indexOf(',')+1));
    };
    reader.readAsDataURL(blob);
}

//example:
var buf = new Uint8Array([11,22,33]);
arrayBufferToBase64(buf, console.log.bind(console)); //"CxYh"

There is another asynchronous way use Blob and FileReader.

I didn't test the performance. But it is a different way of thinking.

function arrayBufferToBase64( buffer, callback ) {
    var blob = new Blob([buffer],{type:'application/octet-binary'});
    var reader = new FileReader();
    reader.onload = function(evt){
        var dataurl = evt.target.result;
        callback(dataurl.substr(dataurl.indexOf(',')+1));
    };
    reader.readAsDataURL(blob);
}

//example:
var buf = new Uint8Array([11,22,33]);
arrayBufferToBase64(buf, console.log.bind(console)); //"CxYh"
满意归宿 2025-01-11 19:34:55

此示例使用内置 FileReader readDataURL() 转换为 Base64 编码。 数据 URL 是结构化的数据:[][;base64],,因此我们在逗号处拆分该 url,并仅返回 base64 编码的字符。

const blob = new Blob([array]);        
const reader = new FileReader();

reader.onload = (event) => {
  const dataUrl = event.target.result;
  const [_, base64] = dataUrl.split(','); 
  // do something with base64
};
   
reader.readAsDataURL(blob);

或者作为承诺的实用程序:

async function encode(array) {
  return new Promise((resolve) => {
    const blob = new Blob([array]);
    const reader = new FileReader();
    
    reader.onload = (event) => {
      const dataUrl = event.target.result;
      const [_, base64] = dataUrl.split(',');
      
      resolve(base64);
    };
    
    reader.readAsDataURL(blob);
  });
}

const encoded = await encode(typedArray);

This example uses the built-in FileReader readDataURL() to do the conversion to base64 encoding. Data URLs are structured data:[<mediatype>][;base64],<data>, so we split that url at the comma and return only the base64 encoded characters.

const blob = new Blob([array]);        
const reader = new FileReader();

reader.onload = (event) => {
  const dataUrl = event.target.result;
  const [_, base64] = dataUrl.split(','); 
  // do something with base64
};
   
reader.readAsDataURL(blob);

Or as a promisified utility:

async function encode(array) {
  return new Promise((resolve) => {
    const blob = new Blob([array]);
    const reader = new FileReader();
    
    reader.onload = (event) => {
      const dataUrl = event.target.result;
      const [_, base64] = dataUrl.split(',');
      
      resolve(base64);
    };
    
    reader.readAsDataURL(blob);
  });
}

const encoded = await encode(typedArray);
长安忆 2025-01-11 19:34:55

我用过这个并且为我工作。

function arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}



function base64ToArrayBuffer(base64) {
    var binary_string =  window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array( len );
    for (var i = 0; i < len; i++)        {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}

I used this and works for me.

function arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}



function base64ToArrayBuffer(base64) {
    var binary_string =  window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array( len );
    for (var i = 0; i < len; i++)        {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}
岁月如刀 2025-01-11 19:34:55

我对此的建议是不要使用本机 btoa 策略,因为它们无法正确编码所有 ArrayBuffer 的…

重写 DOM atob() 并btoa()

由于 DOMString 是 16 位编码的字符串,因此在大多数浏览器中,如果字符超出 8 位 ASCII 编码字符的范围,则在 Unicode 字符串上调用 window.btoa 将导致字符超出范围异常。

虽然我从未遇到过这个确切的错误,但我发现我尝试编码的许多 ArrayBuffer 编码不正确。

我要么使用 MDN 推荐,要么使用 gist。

My recommendation for this is to NOT use native btoa strategies—as they don't correctly encode all ArrayBuffer's…

rewrite the DOMs atob() and btoa()

Since DOMStrings are 16-bit-encoded strings, in most browsers calling window.btoa on a Unicode string will cause a Character Out Of Range exception if a character exceeds the range of a 8-bit ASCII-encoded character.

While I have never encountered this exact error, I have found that many of the ArrayBuffer's I have tried to encode have encoded incorrectly.

I would either use MDN recommendation or gist.

献世佛 2025-01-11 19:34:55

下面是两个简单的函数,用于将 Uint8Array 转换为 Base64 字符串并再次转换回来

arrayToBase64String(a) {
    return btoa(String.fromCharCode(...a));
}

base64StringToArray(s) {
    let asciiString = atob(s);
    return new Uint8Array([...asciiString].map(char => char.charCodeAt(0)));
}

Below are 2 simple functions for converting Uint8Array to Base64 String and back again

arrayToBase64String(a) {
    return btoa(String.fromCharCode(...a));
}

base64StringToArray(s) {
    let asciiString = atob(s);
    return new Uint8Array([...asciiString].map(char => char.charCodeAt(0)));
}
口干舌燥 2025-01-11 19:34:55

在 Node.js 中(即不是浏览器):

Buffer.from(myArrayBuffer).toString("base64");

In Node.js (i.e. not browser):

Buffer.from(myArrayBuffer).toString("base64");
画▽骨i 2025-01-11 19:34:55

如果您同意添加库,base64-arraybuffer

yarn add base64-arraybuffer

那么:

  • encode(buffer) - 将 ArrayBuffer 编码为 Base64 字符串
  • decode(str) - 将 Base64 字符串解码为 ArrayBuffer

If you're okay with adding a library, base64-arraybuffer:

yarn add base64-arraybuffer

then:

  • encode(buffer) - Encodes ArrayBuffer into base64 string
  • decode(str) - Decodes base64 string to ArrayBuffer
皓月长歌 2025-01-11 19:34:55
ABtoB64(ab) {
    return new Promise(res => {
        const fr = new FileReader();
        fr.onload = ({target: {result: s}}) => res(s.slice(s.indexOf(';base64,') + 8));
        fr.readAsDataURL(new Blob([ab]));
    });
}

使用文件读取器的异步方法。

ABtoB64(ab) {
    return new Promise(res => {
        const fr = new FileReader();
        fr.onload = ({target: {result: s}}) => res(s.slice(s.indexOf(';base64,') + 8));
        fr.readAsDataURL(new Blob([ab]));
    });
}

asynchronous method using file reader.

我不在是我 2025-01-11 19:34:55

我使用 TextDecode api 将其转换为普通文本,然后将其转换为 Base64

const uint =  new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]).buffer
const decoder = new TextDecoder()
const decodedText = decoder.decode(uint)
const base64Code = btoa(decodedText)

i use TextDecode api to convert it to normal text and then convert it to Base64

const uint =  new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]).buffer
const decoder = new TextDecoder()
const decodedText = decoder.decode(uint)
const base64Code = btoa(decodedText)
简美 2025-01-11 19:34:55

在浏览器中,使用 btoa 建议的解决方案似乎不错。
但在 Node.js 中 btoa 已成为旧版

建议使用 buffer.toString(encoding)

const myString = buffer.toString("base64")

In the Browser suggested solutions with btoa seem fine.
But in Node.js btoa is Legacy

It is recommended to use buffer.toString(encoding)

like

const myString = buffer.toString("base64")

小巷里的女流氓 2025-01-11 19:34:55

这是一个 ES6 解决方案,比使用原生 btoa 函数快 3 倍,比 mobz 和 Emmanuel 提出的非原生解决方案快 1.25 倍。它的代码还尊重最新的良好编码实践,并使用更干净的二进制掩码以提高可读性:

    /**
     * @param {ArrayBuffer} buffer
     * @return {string}
     */
    function toBase64(buffer) {
        const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        const byteLength = buffer.byteLength;
        const bufferView = new Uint8Array(buffer);
        const remainingBytesCount = byteLength % 3;
        const mainLength = byteLength - remainingBytesCount;

        let string = "";
        let i = 0;

        for (; i < mainLength; i += 3) {
            const chunk = (bufferView[i] << 16) | (bufferView[i + 1] << 8) | bufferView[i + 2];
            string += base64Chars[(chunk & 0b111111000000000000000000) >> 18];
            string += base64Chars[(chunk & 0b000000111111000000000000) >> 12];
            string += base64Chars[(chunk & 0b000000000000111111000000) >> 6];
            string += base64Chars[(chunk & 0b000000000000000000111111)];
        }

        if (remainingBytesCount === 2) {
            const chunk = (bufferView[i] << 16) | (bufferView[i + 1] << 8);
            string += base64Chars[(chunk & 0b111111000000000000000000) >> 18];
            string += base64Chars[(chunk & 0b000000111111000000000000) >> 12];
            string += base64Chars[(chunk & 0b000000000000111111000000) >> 6];
            string += "=";

        } else if (remainingBytesCount === 1) {
            const chunk = (bufferView[i] << 16);
            string += base64Chars[(chunk & 0b111111000000000000000000) >> 18];
            string += base64Chars[(chunk & 0b000000111111000000000000) >> 12];
            string += "==";
        }

        return string;
    }

Here is a ES6 solution that is 3 times faster than using the native btoa function and is 1.25 faster than the non-native solution proposed by mobz and Emmanuel. Its code also respect more recent good coding practices and uses way more clean binary masks for readability :

    /**
     * @param {ArrayBuffer} buffer
     * @return {string}
     */
    function toBase64(buffer) {
        const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        const byteLength = buffer.byteLength;
        const bufferView = new Uint8Array(buffer);
        const remainingBytesCount = byteLength % 3;
        const mainLength = byteLength - remainingBytesCount;

        let string = "";
        let i = 0;

        for (; i < mainLength; i += 3) {
            const chunk = (bufferView[i] << 16) | (bufferView[i + 1] << 8) | bufferView[i + 2];
            string += base64Chars[(chunk & 0b111111000000000000000000) >> 18];
            string += base64Chars[(chunk & 0b000000111111000000000000) >> 12];
            string += base64Chars[(chunk & 0b000000000000111111000000) >> 6];
            string += base64Chars[(chunk & 0b000000000000000000111111)];
        }

        if (remainingBytesCount === 2) {
            const chunk = (bufferView[i] << 16) | (bufferView[i + 1] << 8);
            string += base64Chars[(chunk & 0b111111000000000000000000) >> 18];
            string += base64Chars[(chunk & 0b000000111111000000000000) >> 12];
            string += base64Chars[(chunk & 0b000000000000111111000000) >> 6];
            string += "=";

        } else if (remainingBytesCount === 1) {
            const chunk = (bufferView[i] << 16);
            string += base64Chars[(chunk & 0b111111000000000000000000) >> 18];
            string += base64Chars[(chunk & 0b000000111111000000000000) >> 12];
            string += "==";
        }

        return string;
    }
沉溺在你眼里的海 2025-01-11 19:34:55

您可以使用 Array.prototype.slice 从 ArrayBuffer 派生普通数组。
使用 Array.prototype.map 等函数将字节转换为字符,并将它们连接在一起形成字符串。

function arrayBufferToBase64(ab){

    var dView = new Uint8Array(ab);   //Get a byte view        

    var arr = Array.prototype.slice.call(dView); //Create a normal array        

    var arr1 = arr.map(function(item){        
      return String.fromCharCode(item);    //Convert
    });

    return window.btoa(arr1.join(''));   //Form a string

}

此方法速度更快,因为其中没有运行字符串连接。

You can derive a normal array from the ArrayBuffer by using Array.prototype.slice.
Use a function like Array.prototype.map to convert bytes in to characters and join them together to forma string.

function arrayBufferToBase64(ab){

    var dView = new Uint8Array(ab);   //Get a byte view        

    var arr = Array.prototype.slice.call(dView); //Create a normal array        

    var arr1 = arr.map(function(item){        
      return String.fromCharCode(item);    //Convert
    });

    return window.btoa(arr1.join(''));   //Form a string

}

This method is faster since there are no string concatenations running in it.

↙厌世 2025-01-11 19:34:55
 var uint8Array = new Uint8Array(BytesArray);

 var base64Str = btoa(String.fromCharCode(...uint8Array));

 Or,

 var base64Str = btoa(uint8Array.reduce((x, y) => x + String.fromCharCode(y), ''));
 var uint8Array = new Uint8Array(BytesArray);

 var base64Str = btoa(String.fromCharCode(...uint8Array));

 Or,

 var base64Str = btoa(uint8Array.reduce((x, y) => x + String.fromCharCode(y), ''));
尝蛊 2025-01-11 19:34:55

Uint8Array.prototype.toBase64很快实施浏览器!

然后您将能够编写:

const arr = new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]);
arr.toBase64(); // SSBsb3ZlIHlvdQ==

您还可以使用 这个 core-js 填充

const arr = new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]);
const base64 = arr.toBase64();

console.log(base64);
<script src="https://unpkg.com/[email protected]/minified.js"></script>

Uint8Array.prototype.toBase64 will soon be implemented on the browser!

You will then be able to write:

const arr = new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]);
arr.toBase64(); // SSBsb3ZlIHlvdQ==

You can also use this core-js polyfill:

const arr = new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]);
const base64 = arr.toBase64();

console.log(base64);
<script src="https://unpkg.com/[email protected]/minified.js"></script>

谈下烟灰 2025-01-11 19:34:55

使用 uint8-to-b64 包来做浏览器和 Node.js 中的编码/解码

Use uint8-to-b64 package to do encoding/decoding in browser and Node.js

Smile简单爱 2025-01-11 19:34:55

在我这边,使用 Chrome 导航器,我必须使用 DataView() 来读取 arrayBuffer

function _arrayBufferToBase64( tabU8A ) {
var binary = '';
let lecteur_de_donnees = new DataView(tabU8A);
var len = lecteur_de_donnees.byteLength;
var chaine = '';
var pos1;
for (var i = 0; i < len; i++) {
    binary += String.fromCharCode( lecteur_de_donnees.getUint8( i ) );
}
chaine = window.btoa( binary )
return chaine;}

By my side, using Chrome navigator, I had to use DataView() to read an arrayBuffer

function _arrayBufferToBase64( tabU8A ) {
var binary = '';
let lecteur_de_donnees = new DataView(tabU8A);
var len = lecteur_de_donnees.byteLength;
var chaine = '';
var pos1;
for (var i = 0; i < len; i++) {
    binary += String.fromCharCode( lecteur_de_donnees.getUint8( i ) );
}
chaine = window.btoa( binary )
return chaine;}
贪恋 2025-01-11 19:34:55
function _arrayBufferToBase64(uarr) {
    var strings = [], chunksize = 0xffff;
    var len = uarr.length;

    for (var i = 0; i * chunksize < len; i++){
        strings.push(String.fromCharCode.apply(null, uarr.subarray(i * chunksize, (i + 1) * chunksize)));
    }

    return strings.join("");
}

如果您使用 JSZip 从字符串中解压存档,这会更好

function _arrayBufferToBase64(uarr) {
    var strings = [], chunksize = 0xffff;
    var len = uarr.length;

    for (var i = 0; i * chunksize < len; i++){
        strings.push(String.fromCharCode.apply(null, uarr.subarray(i * chunksize, (i + 1) * chunksize)));
    }

    return strings.join("");
}

This is better, if you use JSZip for unpack archive from string

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文