Base64 dizesini ArrayBuffer'a dönüştürme


108

Base64 kodlama dizesini ArrayBuffer'a dönüştürmem gerekiyor. Base64 dizeleri kullanıcı girdisidir, bir e-postadan kopyalanıp yapıştırılırlar, böylece sayfa yüklendiğinde orada olmazlar. Bunu mümkünse sunucuya bir ajax çağrısı yapmadan javascript'te yapmak istiyorum.

Bu bağlantıları ilginç buldum ama bana yardımcı olmadılar:

ArrayBuffer'dan base64 kodlu dizeye

bu, ArrayBuffer'dan base64'e zıt dönüşümle ilgili, tersi değil

http://jsperf.com/json-vs-base64/2

bu iyi görünüyor ancak kodu nasıl kullanacağımı çözemiyorum.

Dönüştürmeyi yapmanın kolay (belki yerel) bir yolu var mı? Teşekkürler

Yanıtlar:


155

Bunu dene:

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

4
Lütfen bana burada gerçekte neler olduğunu açıklayın.
Govinda Sakhare

4
Oldukça basit, önce base64 dizesini (atob) çözeriz, sonra kodu çözülen dizeyle aynı uzunlukta 8 bitlik işaretsiz tamsayılardan oluşan yeni bir dizi oluştururuz. Bundan sonra dizeyi yineliyoruz ve diziyi dizedeki her karakterin Unicode değeri ile dolduruyoruz.
Goran.it

2
MDN'den: Base64, ASCII dizgi formatında ikili verileri radix-64 gösterimine çevirerek temsil eden benzer ikili-metne kodlama şemaları grubudur. Uint8Array tipi dizi, 8 bitlik işaretsiz tamsayılardan oluşan bir diziyi temsil eder ve verilerin ASCII gösterimi ile çalışıyoruz (ki bu da 8 bitlik bir tablodur) ..
Goran.it

3
Bu doğru değil. Javascript'in baytları dize olarak yorumlamasına izin verir, bu da gerçekte gerçek ikili olan verileri etkiler.
Tomáš Zato - Monica'yı eski durumuna döndür

4
sorun şu ki a) her bayt dizisi geçerli unicode değildir b) unicode'daki her karakter bir bayt değildir, bu yüzden bytes[i] = binary_string.charCodeAt(i);yanlış olabilir
karışım

57

TypedArray.from kullanarak :

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))

Goran.it'in for loop sürümü ile karşılaştırılacak performans cevap.


2
Bu tür bir astarı sevenler için Uint8Array.from, bazı tarayıcılarla hala çok az uyumluluğa sahip olduğunu unutmayın .
IzumiSy

2
Lütfen atob veya btoa'yı önermeyin: developer.mozilla.org/en-US/docs/Web/API/WindowBase64/…
Kugel

rails derleyicisi bu dizeyi işleyemez ve başarısız olur ExecJS::RuntimeError: SyntaxError: Unexpected token: operator (>); (raylar 5)
Avael Kross

3
Bu bir dizi tamponu değildir. Bu, yazılan dizidir. Dizi arabelleğine .buffer, döndürülen Uint8Array
öğenin

4
@Saites, yanlış bir şey yok atobya da btoaonlara sadece geçerli girdi vermeniz gerekiyor. atobgeçerli bir base64 dizesine ihtiyaç duyar, aksi takdirde bir hata verir. Ve btoa0-255 aralığındaki karakterleri içeren bir dize olan geçerli bir bayt dizesine (ikili dize olarak da adlandırılır) ihtiyaç duyar. Dizenizde bu aralığın dışında karakterler varsa, btoabir hata atar.
GetFree

35

Goran.it'in yanıtı, javascript'teki unicode sorunu nedeniyle çalışmıyor - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding .

Daniel Guerrero'nun blogunda verilen işlevi kullandım: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

İşlev github bağlantısında listelenmiştir: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

Bu satırları kullanın

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 

1
Bu yöntem, atob kullanmaktan 2 kat daha hızlıdır.
xiaoyu2er

4
İşe yaramayacağı bir örnek verebilir misiniz? Makale, unicode karakterler içerebilen, ancak bunlar için hiç geçerli olmayan rastgele dizelerin kodlanmasından bahsediyor atob.
riv

1
decodeArrayBufferArrayBufferboyutu her zaman 3'e bölünebilen bir döndürür , ki bunun tasarımdan mı yoksa bir hatadan mı kaynaklandığını anlamıyorum. Github projesinde soracağım.
ceztko

@ceztko Muhtemelen (tesadüfi) tasarım gereğidir. Base64 kodlama algoritması, 3 baytlık grupları alır ve bunları 4 karaktere dönüştürür. Kod çözme yöntemi muhtemelen uzunluğu base64String.length / 4 * 3 bayt olan bir ArrayBuffer ayırır ve bittiğinde kullanılmayan baytları asla kesmez.
AlwaysLearning

1
@AlwaysLearning, artık sıfır baytlık amaçlanan çıktı içeriğini bozabileceğinden muhtemelen hata verdiği anlamına gelir.
ceztko


10

Zaman uyumsuz çözüm, veriler büyük olduğunda daha iyidir:

// base64 to buffer
function base64ToBufferAsync(base64) {
  var dataUrl = "data:application/octet-binary;base64," + base64;

  fetch(dataUrl)
    .then(res => res.arrayBuffer())
    .then(buffer => {
      console.log("base64 to buffer: " + new Uint8Array(buffer));
    })
}

// buffer to base64
function bufferToBase64Async( buffer ) {
    var blob = new Blob([buffer], {type:'application/octet-binary'});    
    console.log("buffer to blob:" + blob)

    var fileReader = new FileReader();
    fileReader.onload = function() {
      var dataUrl = fileReader.result;
      console.log("blob to dataUrl: " + dataUrl);

      var base64 = dataUrl.substr(dataUrl.indexOf(',')+1)      
      console.log("dataUrl to base64: " + base64);
    };
    fileReader.readAsDataURL(blob);
}

8

Node.js kullanıcıları için:

const myBuffer = Buffer.from(someBase64String, 'base64');

myBuffer, Uint8Array'in bir alt sınıfı olan Buffer türünde olacaktır. Ne yazık ki, Uint8Array, OP'nin istediği gibi bir ArrayBuffer DEĞİLDİR. Ancak bir ArrayBuffer'ı işlerken neredeyse her zaman onu Uint8Array veya benzeri bir şeyle paketlerim, bu yüzden istenene yakın olmalıdır.


6

Javascript iyi bir geliştirme ortamıdır, bu yüzden bu küçük soruna bir çözüm sağlamadığından garip görünüyor. Bu sayfada başka yerlerde sunulan çözümler potansiyel olarak yavaştır. İşte benim çözümüm. Base64 görüntü ve ses veri url'lerinin kodunu çözen dahili işlevselliği kullanır.

var req = new XMLHttpRequest;
req.open('GET', "data:application/octet;base64," + base64Data);
req.responseType = 'arraybuffer';
req.onload = function fileLoaded(e)
{
   var byteArray = new Uint8Array(e.target.response);
   // var shortArray = new Int16Array(e.target.response);
   // var unsignedShortArray = new Int16Array(e.target.response);
   // etc.
}
req.send();

Temel 64 dizesi kötü biçimlendirilmişse gönderme isteği başarısız olur.

Mime türü (uygulama / octet) muhtemelen gereksizdir.

Chrome'da test edildi. Diğer tarayıcılarda çalışmalıdır.


1
Bu benim için mükemmel bir çözümdü, basit ve temiz. Firefox, IE 11, Edge'de hızlı bir şekilde test ettim ve iyi çalıştı!
cs-NET

IE11'de sizin için nasıl çalıştığından emin değilim, ancak Access Deniedbir CORS sınırlaması gibi görünen bir hata alıyorum.
Sergiu

2

Saf JS - dizi orta adım yok (atob yok)

Base64'ü doğrudan (middlestep'te dizgeye dönüştürmeden) dönüştüren aşağıdaki işlevi yazıyorum. FİKİR

  • 4 adet base64 karakter parçası alın
  • base64 alfabesinde her karakterin dizinini bulun
  • indeksi 6 bitlik sayıya dönüştür (ikili dize)
  • 24 bitlik sayı veren dört 6 bit sayıyı birleştirin (ikili dizi olarak saklanır)
  • 24-bit dizgiyi üç adet 8-bit'e bölün ve her birini sayıya çevirin ve çıktı dizisinde saklayın
  • köşe durumu: eğer girdi base64 dizesi bir / iki =karakterle bitiyorsa , çıktı dizisinden bir / iki sayıyı kaldırın

Aşağıdaki çözüm, büyük girdi base64 dizelerini işlemeye izin verir. Baytları btoa olmadan base64'e dönüştürmek için benzer işlev BURADA


yani eksik "." yok mu?
Gillsoft AB

Bir tarayıcıda test edin, bunun beklenen sonuç olduğundan emin değil misiniz? "Alice Harikalar Diyarında " (yani son karakter
NaN'dir

1
@GillsoftAB Bu bilgi için teşekkür ederim - haklısınız - Sorunu
çözüyorum

0

Base64 belirtimini doğru bir şekilde uygulayan bir npm paketi kullanmanızı şiddetle tavsiye ederim.

Bildiğim en iyisi rfc4648

Sorun şu ki, btoa ve atob Uint8Array yerine ikili dizeler kullanıyor ve ondan dönüştürmeye çalışmak zahmetli. Ayrıca bunun için npm'de birçok kötü paket var. Onu bulmadan önce çok zaman kaybediyorum.

Bu özel paketin yaratıcıları basit bir şey yaptılar: Base64 spesifikasyonunu aldılar (bu arada burada ) ve baştan sona doğru şekilde uyguladılar. (Spesifikasyondaki Base64-url, Base32, vb. Gibi yararlı olan diğer biçimler dahil) Bu çok fazla görünmüyor ama görünüşe göre bu diğer kitaplıklara sorulamayacak kadar fazlaydı.

Yani evet, biraz din propagandası yaptığımı biliyorum ama zamanınızı da kaybetmemek istiyorsanız sadece rfc4648'i kullanın.


-4
const str = "dGhpcyBpcyBiYXNlNjQgc3RyaW5n"
const encoded = new TextEncoder().encode(str) // is Uint8Array
const buf = encoded.buffer // is ArrayBuffer

6
Bunun Base64 kod çözme / kodlama yapmadığını unutmayın. Sadece "base64" ün 6 baytını 6 elemanlı ArrayBuffer veya Uint8Array'e dönüştürür.
dubek

2
@dubek sorulan buydu.
Andrii Nemchenko
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.