base64로 인코딩 된 문자열에 대한 ArrayBuffer


203

ArrayBuffermultipart 게시물에서 사용해야하는 base64 문자열 로 변환하는 효율적인 (원시 읽기) 방법 이 필요합니다.

답변:


221
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 참조


10
링크에서 네이티브가 아닌 구현을 시도했으며 1M 크기 버퍼를 변환하는 데 1 분 반이 걸렸지 만 루프 코드는 1 초 밖에 걸리지 않았습니다.
cshu

1
나는이 접근법의 단순함을 좋아하지만 모든 문자열 연결은 비용이 많이들 수 있습니다. join()Firefox, IE 및 Safari에서 문자 배열을 작성하고 마지막에 문자를 입력 하는 것이 훨씬 빠릅니다 (그러나 Chrome에서는 상당히 느립니다) : jsperf.com/tobase64-implementations
JLRishe

이 함수를 배열 버퍼에서 base64로 변환하는 데 사용하지만 배열 버퍼를 다시 가져올 수 없습니다. 여기에 _base64ToArrayBuffer () 함수를 작성했습니다. codeshare.io/PT4pb 그러나 다음과 같은 오류가 발생합니다.Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
bawejakunal

이 JSZip에서는 작동하지 않습니다. github.com/michael/github/issues/137
RouR

1
angualrjs 및 webapi2를 사용하여 50MB pdf 파일 업로드를 시도하고 있습니다. 위의 코드를 사용하고 있습니다. 파일을 업로드 한 후 페이지가 다운되어 중단되었습니다. 아래 코드 줄에서 webapi 메서드에서 null 값을 얻었지만 사용되었습니다. "var base64String = btoa (String.fromCharCode.apply (null, new Uint8Array (arrayBuffer)));" 어떤 아이디어를 제안하십시오 ...
prabhakaran S

102

이것은 나를 위해 잘 작동합니다 :

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

ES6에서 구문은 조금 더 간단합니다.

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

주석에서 지적 했듯이이 방법은 일부 브라우저에서 런타임 오류가 발생할 수 있습니다 ArrayBuffer. 정확한 크기 제한은 구현에 따라 다릅니다.


38
간결함을 위해이 방법을 선호하지만 "최대 호출 스택 크기 초과 오류"가 발생합니다. 위의 루프 기술은 그 문제를 해결합니다.
Jay

13
또한 스택 크기 오류가 발생하므로 mobz의 답변을 사용하여 훌륭하게 작동했습니다.
David Jones

12
큰 버퍼에서는 작동하지 않았습니다. 작동을위한 약간의 수정 :btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''))
laggingreflex

1
angualrjs 및 webapi2를 사용하여 50MB pdf 파일 업로드를 시도하고 있습니다. 위의 코드를 사용하고 있습니다. 파일을 업로드 한 후 페이지가 다운되어 중단되었습니다. 아래 코드 줄에서 webapi 메서드에서 null 값을 얻었지만 사용되었습니다. "var base64String = btoa (String.fromCharCode.apply (null, new Uint8Array (arrayBuffer)));" 어떤 아이디어를 제안하십시오 ...
prabhakaran S

2
@Kugel btoa은 코드 범위 0-255의 문자에 안전합니다 Uint8Array.
GOTO 0

42

짧게 좋아하는 사람들을 위해 Array.reduce스택 오버플로를 발생시키지 않는 다른 사용 방법 이 있습니다.

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

4
그것이 정말로 섹시한지 확실하지 않습니다. 결국, 당신은 <amount of Bytes in the buffer>새로운 문자열을 만들고 있습니다.
Neonit

어때요 btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(String.fromCharCode(byte)),data),[]).join(''))?
Roy Tinker

35

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).
카터 메 드린

이것이 작동한다고 보장되지는 않습니다. w3c.github.io/FileAPI/#issue-f80bda5b 에 따르면 readAsDataURL 이론적으로 dataURI 인코딩 퍼센트를 반환 (그리고 실제로의 경우 것 같다 수 jsdom )
TS

@CarterMedlin 왜 split보다 나은가 substring?
TS

분할이 더 짧습니다. 그러나 dataurl은 하나 이상의 쉼표 (,)를 포함 할 수 있지만 split은 안전하지 않습니다.
cuixiping 2018 년

12

나는 이것을 사용했고 나를 위해 일했다.

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

안전하지 않음. @chemoish 답변보기
Kugel

11

이것에 대한 나의 추천은 네이티브를 사용하지 않는 것입니다 btoa 전략을 하지 않는 것입니다 ArrayBuffer.

DOM atob () 및 btoa ()를 다시 작성하십시오.

DOMString은 16 비트 인코딩 된 문자열이므로 유니 코드 문자열에서 window.btoa를 호출하는 대부분의 브라우저에서 문자가 8 비트 ASCII 인코딩 문자의 범위를 초과하면 범위를 벗어난 문자 예외가 발생합니다.

이 정확한 오류가 발생하지는 않았지만 ArrayBuffer 인코딩하려고 시도한의 잘못 인코딩 된 .

MDN 권장 사항 또는 요지를 사용합니다.


btoaString에서는 작동하지 않지만 OP는 묻습니다 ArrayBuffer.
tsh

1
매우 많은, 여기에 잘못된 것을 추천하는 많은 스 니펫이 있습니다! 사람들이 atob과 btoa를 맹목적으로 사용하는이 오류를 여러 번 보았습니다.
Kugel

4
atob / btoa는 0xFF보다 큰 문자를 포함하는 텍스트의 경우에만 문제가됩니다 (정의에 의한 바이트 배열은 그렇지 않음). MDN 경고는 다른 답변에서 전략을 사용할 때 Uint8Array의 값이 0과 255 사이임을 보증하므로 ASCII 문자로만 구성된 문자열을 보장하므로 String.fromCharCode가 보장되므로 적용되지 않습니다. 범위를 벗어난 문자를 반환합니다.
Jamesernator

11
var blob = new Blob([arrayBuffer])

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

reader.readAsDataURL(blob);

1
답변에 설명을 추가하십시오. 이 코드는 무엇을 의미합니까?
Oscar


1
이것은 제한 테스트에서 다른 방법보다 수십 배 더 빠릅니다
jitin

이 솔루션을 다시 8 시간 정도 찾았 으면 좋겠다. 내 하루는 낭비되지 않았을 것입니다. (감사합니다
Kaiser Shahid

7

다음은 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)));
}

1
이것은 혼란스러운 답변입니다. 유효한 JavaScript처럼 보이지 않으며 Uint8Array는 ArrayBuffer입니까?
user1153660

@ user1153660 function키워드를 추가하면 최신 브라우저에서 작동합니다.
Yeti

대박! btoa (String.fromCharCode (... a)); Uint8Array를 인코딩하기 위해 지금까지 본 가장 짧은 버전입니다.
Nicolo

1
이것은 좋아 보이지만 배열이 너무 크면 최대 호출 스택 크기 초과 오류가 발생합니다.
Paweł Psztyć

0

ArrayBuffer를 사용하여 에서 일반 배열을 파생시킬 수 있습니다 Array.prototype.slice. Array.prototype.map바이트를 문자로 변환 join하고 함께 문자열을 형식화 하는 것과 같은 함수를 사용하십시오 .

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

}

이 방법은 문자열 연결이 없기 때문에 더 빠릅니다.


안전하지 않음. @chemoish 답변보기
Kugel

0

OP는 Running Enviroment를 지정하지 않았지만 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에서 실행중인 경우 버퍼 환경은 브라우저 환경에서도 사용할 수 있습니다.


귀하의 답변은 NodeJS에만 적용되며 브라우저에서 작동하지 않습니다.
jvatic

1
@ jvatic 나는 OP가 Running Environment를 명확하게 지정하지 않았기 때문에 내 대답이 잘못되지 않았으며 그는 태그 만했습니다 Javascript. 그래서 나는 더 간결하게하기 위해 대답을 업데이트했습니다. 나는 이것을하는 방법을 찾고 있었고 문제에 대한 최상의 대답을 얻지 못했기 때문에 이것이 중요한 대답이라고 생각합니다.
João Eduardo Soares e Silva

-3

내 옆에 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;}

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

문자열에서 압축 파일을 풀 때 JSZip을 사용하는 것이 좋습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.