ฉันต้องการวิธีที่มีประสิทธิภาพ (อ่านพื้นเมือง) เพื่อแปลงArrayBuffer
เป็นสตริง base64 ซึ่งจำเป็นต้องใช้ในการโพสต์หลายส่วน
ฉันต้องการวิธีที่มีประสิทธิภาพ (อ่านพื้นเมือง) เพื่อแปลงArrayBuffer
เป็นสตริง base64 ซึ่งจำเป็นต้องใช้ในการโพสต์หลายส่วน
คำตอบ:
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
join()
ท้ายที่สุดจะเร็วขึ้นอย่างมากบน Firefox, IE และ Safari (แต่ค่อนข้างช้ากว่ามากใน Chrome): jsperf.com/tobase64-implementations
Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
มันใช้งานได้ดีสำหรับฉัน:
var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
ใน ES6 ไวยากรณ์นั้นง่ายกว่าเล็กน้อย:
let base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
ตามที่ระบุไว้ในความคิดเห็นวิธีนี้อาจทำให้เกิดข้อผิดพลาดรันไทม์ในเบราว์เซอร์บางตัวเมื่อArrayBuffer
มีขนาดใหญ่ การ จำกัด ขนาดที่แน่นอนนั้นขึ้นอยู่กับการใช้งานในทุกกรณี
btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''))
btoa
มีความปลอดภัยสำหรับตัวอักษรในช่วงรหัส 0-255 เช่นนี้เป็นกรณี (คิดเกี่ยวกับ 8 ในUint8Array
)
สำหรับคนที่ชอบสั้น ๆ นี่คืออีกคนที่ใช้Array.reduce
ซึ่งจะไม่ทำให้เกิดการล้นสแต็ค:
var base64 = btoa(
new Uint8Array(arrayBuffer)
.reduce((data, byte) => data + String.fromCharCode(byte), '')
);
<amount of Bytes in the buffer>
ท้ายที่สุดคุณกำลังสร้างสตริงใหม่
btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(String.fromCharCode(byte)),data),[]).join(''))
ล่ะ
มีอีกวิธีใช้แบบอะซิงโครนัสใช้ 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"
dataurl.split(',', 2)[1]
dataurl.substr(dataurl.indexOf(',')+1)
readAsDataURL
ทางทฤษฎีสามารถคืนค่าการเข้ารหัสเปอร์เซ็นต์ datauri (และดูเหมือนว่าจริง ๆ แล้วมันเป็นjsdom )
split
จะดีกว่าsubstring
?
ฉันใช้มันและทำงานให้ฉัน
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;
}
คำแนะนำของฉันสำหรับสิ่งนี้คือการไม่ใช้btoa
กลยุทธ์ดั้งเดิม- เนื่องจากไม่ได้เข้ารหัสอย่างถูกต้องทั้งหมดArrayBuffer
...
เขียน DOMs atob () และ btoa () อีกครั้ง
เนื่องจาก DOMStrings เป็นสตริงที่มีการเข้ารหัส 16 บิตในเบราว์เซอร์ส่วนใหญ่ที่เรียก window.btoa บนสตริง Unicode จะทำให้เกิดข้อยกเว้น Character Out Of Range หากอักขระเกินช่วงของอักขระที่เข้ารหัส ASCII 8 บิต
ในขณะที่ฉันไม่เคยพบข้อผิดพลาดที่แน่นอนนี้ฉันพบว่ามีหลายคนที่ArrayBuffer
ฉันพยายามเข้ารหัสได้เข้ารหัสอย่างไม่ถูกต้อง
ฉันจะใช้คำแนะนำหรือส่วนสำคัญของ MDN
btoa
ไม่ได้ทำงานบนเชือก แต่ OP ArrayBuffer
จะขอ
var blob = new Blob([arrayBuffer])
var reader = new FileReader();
reader.onload = function(event){
var base64 = event.target.result
};
reader.readAsDataURL(blob);
ด้านล่างนี้เป็นฟังก์ชั่นง่าย ๆ สำหรับการแปลง Uint8Array เป็น Base64 String และกลับมาอีกครั้ง
arrayToBase64String(a) {
return btoa(String.fromCharCode(...a));
}
base64StringToArray(s) {
let asciiString = atob(s);
return new Uint8Array([...asciiString].map(char => char.charCodeAt(0)));
}
function
คำหลักและควรทำงานในเบราว์เซอร์ที่ทันสมัย
คุณสามารถได้รับอาร์เรย์ปกติจากโดยใช้ArrayBuffer
Array.prototype.slice
ใช้ฟังก์ชันที่ต้องการArray.prototype.map
แปลงไบต์เป็นอักขระและjoin
รวมกันเป็นสตริง forma
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
}
วิธีนี้เร็วกว่าเนื่องจากไม่มีการต่อข้อมูลสตริง
OP ไม่ได้ระบุสภาพแวดล้อมการทำงาน แต่ถ้าคุณใช้ Node.JS มีวิธีง่าย ๆ ในการทำสิ่งนั้น
สอดคล้องกับ 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');
นอกจากนี้หากคุณกำลังทำงานภายใต้ Angular ตัวอย่างเช่น Buffer Class จะให้บริการในสภาพแวดล้อมของเบราว์เซอร์
Javascript
ไม่ได้อย่างชัดเจนระบุเล่นสิ่งแวดล้อมดังนั้นคำตอบของฉันไม่ได้ไม่ถูกต้องเขาแท็กเท่านั้น ดังนั้นฉันจึงปรับปรุงคำตอบเพื่อให้กระชับยิ่งขึ้น ฉันคิดว่านี่เป็นคำตอบที่สำคัญเพราะฉันกำลังค้นหาวิธีการทำสิ่งนี้และไม่สามารถหาคำตอบที่ดีที่สุดสำหรับปัญหาได้
ข้างๆฉันเมื่อใช้การนำทาง 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;}
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 เพื่อคลายการบีบอัดไฟล์จากสตริง