ArrayBuffer - base64 kodlu dize


203

Ben dönüştürmek için verimli (okuma yerel) bir yol ArrayBuffergerekir bir çok parçalı yazı üzerinde kullanılması gereken bir base64 dize.

Yanıtlar:


222
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 );
}

ancak yerel olmayan uygulamalar daha hızlıdır, örneğin https://gist.github.com/958841 bkz. http://jsperf.com/encoding-xhr-image-data/6


10
Bağlantıdan yerli olmayan uygulamayı denedim ve yukarıdaki döngü kodu sadece 1 saniye sürdü 1M boyut tampon dönüştürmek için 1 dakika ve yarım sürdü.
cshu

2
Bu yaklaşımın basitliğini seviyorum, ancak tüm bu dize birleştirme pahalı olabilir. join()Firefox, IE ve Safari'de bir dizi karakter oluşturmak ve sonunda bunları yazmak daha hızlıdır (ancak Chrome'da çok daha yavaştır): jsperf.com/tobase64-implementations
JLRishe

Base64 dönüşüm dizi tampon için bu işlevi kullanıyorum ama dizi tampon geri alamıyorum. Ben burada bir _base64ToArrayBuffer () işlevi yazdım: codeshare.io/PT4pb ama bu bana bir hata verir:Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
bawejakunal

bu bu JSZip çalışmıyor. başka bir yol bulmak github.com/michael/github/issues/137
RouR

1
Angualrjs ve webapi2 kullanarak 50mb pdf dosyası yükleme çalışıyorum. Dosyayı yükledikten sonra, yukarıdaki satır kodunu kullanıyorum, sayfa çöktü ve astı. Kod satırının altında kullanıldım ancak webapi yönteminde boş değer elde ettim. "var base64String = btoa (String.fromCharCode.apply (null, yeni Uint8Array (arrayBuffer)));" lütfen herhangi bir fikir önerin ...
prabhakaran S

103

Bu benim için iyi çalışıyor:

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

ES6'da sözdizimi biraz daha basittir:

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

Yorumlarda belirtildiği gibi, bu yöntem ArrayBufferbüyük olduğunda bazı tarayıcılarda bir çalışma zamanı hatasına neden olabilir . Kesin boyut sınırı her durumda uygulamaya bağlıdır.


38
Ben özlü olması için daha iyi bu yöntemi seviyorum, ama bir "maksimum çağrı yığını boyutu aşıldı hatası" olsun. Yukarıdaki döngü tekniği bunun etrafında döner.
Jay

13
Ayrıca yığın boyutu hatası alıyorum, bu yüzden mobz'ın cevabını kullandım ve harika çalıştı.
David Jones

12
Büyük tamponlar için işe yaramadı. btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''))
Çalıştırmak

1
Angualrjs ve webapi2 kullanarak 50mb pdf dosyası yükleme çalışıyorum. Dosyayı yükledikten sonra, yukarıdaki satır kodunu kullanıyorum, sayfa çöktü ve astı. Kod satırının altında kullanıldım ancak webapi yönteminde boş değer elde ettim. "var base64String = btoa (String.fromCharCode.apply (null, yeni Uint8Array (arrayBuffer)));" lütfen herhangi bir fikir önerin ...
prabhakaran S

2
@Kugel btoa0-255 kod aralığındaki karakterler için güvenlidir, çünkü durum burada (8 inç'i düşünün Uint8Array).
GOTO 0

42

Kısa sevenler için, Array.reduceyığın istifine neden olmayacak bir başka kullanım :

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

4
Gerçekten seksi olup olmadığından emin değilim. Sonuçta, <amount of Bytes in the buffer>yeni dizeler oluşturuyorsunuz .
Mart'ta Neonit

Nasıl btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(String.fromCharCode(byte)),data),[]).join(''))?
Roy Tinker

35

Blob ve FileReader'ı kullanmanın başka bir eşzamansız yolu var.

Performansı test etmedim. Fakat bu farklı bir düşünce biçimidir.

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"

Yerine dataurl.split(',', 2)[1]kullanın dataurl.substr(dataurl.indexOf(',')+1).
Carter Medlin

1
Bunun çalışması garanti edilmiyor gibi görünüyor. Göre w3c.github.io/FileAPI/#issue-f80bda5b readAsDataURL teorik dataURI kodlanmış bir yüzde dönmek (Ve aslında olduğu görünüyor olabilir jsdom )
TS

@CarterMedlin Neden daha splitiyi substring?
TS

bölünme daha kısadır. ancak dataurl bir veya daha fazla virgül (,) içerebilir, bölme güvenli değildir.
cuixiping

12

Bunu kullandım ve benim için çalışıyor.

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;
}

Güvenli değil. @Chemoish yanıtına bakın
Kugel

11

Bunun için tavsiyem, yerel btoastratejileri KULLANMAMAKTIR ;ArrayBuffer

atob () ve btoa () DOM'larını yeniden yazma

DOMStrings 16 bit kodlanmış dizeler olduğundan, bir Unicode dizesindeki window.btoa öğesini çağıran çoğu tarayıcıda, bir karakter 8 bit ASCII kodlu bir karakterin aralığını aşarsa Karakter Aralık Dışı İstisnasına neden olur.

Bu tam hatayla hiç karşılaşmamış ArrayBufferolsam da, kodlamaya çalıştığım birçok kodun yanlış kodlandığını gördüm.

Ben ya MDN tavsiye ya da gist kullanırsınız.


btoaString üzerinde çalışmaz, ancak OP soruyor ArrayBuffer.
tsh

1
Çok fazla, burada yanlış bir şey tavsiye çok snippet'ler! Bu hatayı birçok kez gördüm, insanlar körü körüne atob ve btoa kullanıyorlar.
Kugel

4
Tüm dizi arabellekleri diğer yanıtlardaki stratejiler kullanılarak iyi kodlanmalıdır, atob / btoa yalnızca 0xFF'den büyük karakterler içeren (tanım gereği bayt dizileri içermeyen) metinler için bir sorundur. MDN uyarısı geçerli değildir, çünkü diğer cevaplarda stratejiyi kullanırken, Uint8Array öğesinden herhangi bir değerin 0 ile 255 arasında olacağı garanti edildiği için, yalnızca ASCII karakterlerinden oluşan bir dize alacağınız garanti edilir, yani String.fromCharCode garanti edilir aralık dışında bir karakter döndürmek için.
Jamesernator

11
var blob = new Blob([arrayBuffer])

var reader = new FileReader();
reader.onload = function(event){
   var base64 =   event.target.result
};

reader.readAsDataURL(blob);

1
Cevabınıza biraz açıklama ekleyin lütfen. Bu kod ne anlama geliyor?
Oscar


1
Bu, en hızlı yaklaşımdır - sınırlı testlerimde diğerlerinden on kat daha hızlı
jitin

Keşke 8 saat gibi bu çözümü bulsaydım. günüm boşa gitmezdi; (teşekkür ederim
Kaiser Shahid

7

Aşağıda Uint8Array'ı Base64 String'e ve tekrar geri dönüştürmek için 2 basit işlev bulunmaktadır

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

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

1
Bu kafa karıştırıcı bir cevap. Bu geçerli bir JavaScript gibi görünmüyor ve bir Uint8Array bir ArrayBuffer mı?
user1153660

@ user1153660 functionAnahtar kelimeyi ekleyin, modern bir tarayıcıda çalışması gerekir.
Yeti

Müthiş! btoa (String.fromCharCode (... a)); Uint8Array kodlamak için şimdiye kadar gördüğüm en kısa sürümüdür.
Nicolo

1
Bu iyi görünüyor, ancak dizi çok büyükse maksimum çağrı yığını boyutu aşıldı hatası atar.
Paweł Psztyć

0

ArrayBufferKullanarak normal bir dizi türetebilirsiniz Array.prototype.slice. Baytları Array.prototype.mapkarakterlere ve joinbunları birlikte forma dizesine dönüştürmek gibi bir işlev kullanın .

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

}

Bu yöntem, içinde çalışan dize birleştirmeleri olmadığı için daha hızlıdır.


Güvenli değil. @Chemoish yanıtına bakın
Kugel

0

OP, Çalışan Ortamı belirtmedi, ancak Node.JS kullanıyorsanız böyle bir şey yapmanın çok basit bir yolu var.

Resmi Node.JS belgelerine uyum 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');

Ayrıca, örneğin Açısal altında çalıştırıyorsanız, Arabellek Sınıfı da Tarayıcı Ortamında kullanılabilir hale getirilir.


Yanıtınız yalnızca NodeJS için geçerlidir ve tarayıcıda çalışmaz.
jvatic

1
@jvatic Anlıyorum, OP açıkça Koşu Ortamı belirtmedi, bu yüzden cevabım yanlış değil, sadece etiketledi Javascript. Bu yüzden cevabımı daha özlü hale getirmek için güncelledim. Bunun önemli bir cevap olduğunu düşünüyorum çünkü bunu nasıl yapacağımı araştırıyordum ve sorunun en iyi cevabını alamadım.
João Eduardo Soares e Silva

-3

Yanımda, Chrome gezgin kullanarak, bir arrayBuffer okumak için DataView () kullanmak zorunda kaldım

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;}

-4
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("");
}

Arşivi dizeden açmak için JSZip kullanıyorsanız bu daha iyidir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.