문자열과 ArrayBuffer 간 변환


264

JavaScript 문자열을 효율적으로 ArrayBuffer 로 변환 하거나 그 반대로 변환하는 데 일반적으로 사용되는 기술이 있습니까? 특히, ArrayBuffer의 내용을 쓰고 localStorage다시 읽을 수 있기를 바랍니다.


1
나는 이것에 대한 경험이 없지만 API 문서 ( khronos.org/registry/typedarray/specs/latest )에서 판단하면 Int8Array ArrayBufferView대괄호 표기법을 사용하여 문자를 복사 string[i] = buffer[i]하거나 그 반대로 할 수 있습니다.
FK82

2
@ FK82, 이것은 합리적인 접근 방식처럼 보이지만 ( Uint16ArrayJS의 16 비트 문자에 대해 s 사용 ) JavaScript 문자열은 변경할 수 없으므로 문자 위치에 직접 할당 할 수 없습니다. 여전히 String.fromCharCode(x)의 각 값을 Uint16Array일반 에 복사 Array한 다음를 호출 .join()해야합니다 Array.
kpozin

@ kpozin : 사실, 그렇게 생각하지 않았습니다.
FK82

5
@kpozin 대부분의 최신 JS 엔진은 문자열 연결을 최적화하는 것만으로 저렴하게 사용할 수 있습니다 string += String.fromCharCode(buffer[i]);. 문자열과 형식화 된 배열 간 변환을위한 내장 메서드가 없을 것 같습니다. 그들은 이런 일이 일어날 지 알아야했습니다.
다운로드

arrayBuffer.toString () 잘 작동합니다.
시민 conn

답변:


128

2016 년 업데이트 -5 년이 지난 지금 사양에 새로운 인코딩 방법 (아래 지원 참조)이있어 적절한 인코딩을 사용하여 문자열과 유형 배열 사이를 변환합니다.

TextEncoder

는 다음을 TextEncoder나타냅니다 .

TextEncoder인터페이스 같은 특정 문자 인코딩하는 구체적인 방법에 대한 인코더를 나타내고 utf-8,iso-8859-2, koi8, cp1261, gbk, ... 인코더는 코드 포인트 스트림을 입력으로 사용하여 바이트 스트림을 생성합니다.

위의 내용이 기록 된 이후 변경 사항 : (ibid.)

참고 : Firefox, Chrome 및 Opera는 utf-8 이외의 인코딩 유형 (예 : utf-16, iso-8859-2, koi8, cp1261 및 gbk)을 지원했습니다. Firefox 48 [...], Chrome 54 [...] 및 Opera 41에서 사양과 일치시키기 위해 utf-8 이외의 다른 인코딩 유형은 사용할 수 없습니다. *

*) 업데이트 된 사양 (W3) 및 여기 (whatwg)

인스턴스를 만든 후에 TextEncoder는 문자열을 가져와 주어진 인코딩 매개 변수를 사용하여 인코딩합니다.

if (!("TextEncoder" in window)) 
  alert("Sorry, this browser does not support TextEncoder...");

var enc = new TextEncoder(); // always utf-8
console.log(enc.encode("This is a string converted to a Uint8Array"));

그런 다음 .buffer결과 Uint8Array에 매개 변수를 사용하여 ArrayBuffer필요한 경우 언더 레이 를 다른보기 로 변환하십시오 .

문자열의 문자가 인코딩 스키마를 준수하는지 확인하십시오. 예를 들어, 예제에서 UTF-8 범위를 벗어난 문자를 사용하는 경우 1 바이트가 아닌 2 바이트로 인코딩됩니다.

일반적으로 UTF-16 인코딩을 다음과 같은 용도로 사용합니다 localStorage.

TextDecoder

마찬가지로 반대 프로세스 는 다음을 사용합니다TextDecoder .

TextDecoder인터페이스는 특정 문자 인코딩, 추천되는 특정 방법하는 디코더 나타내고 utf-8, iso-8859-2, koi8, cp1261, gbk, ... 디코더 입력으로 바이트 스트림을 취하여 코드 포인트 스트림을 방출한다.

사용 가능한 모든 디코딩 유형은 여기 에서 찾을 수 있습니다 .

if (!("TextDecoder" in window))
  alert("Sorry, this browser does not support TextDecoder...");

var enc = new TextDecoder("utf-8");
var arr = new Uint8Array([84,104,105,115,32,105,115,32,97,32,85,105,110,116,
                          56,65,114,114,97,121,32,99,111,110,118,101,114,116,
                          101,100,32,116,111,32,97,32,115,116,114,105,110,103]);
console.log(enc.decode(arr));

MDN StringView 라이브러리

이에 대한 대안은 StringView라이브러리 (lgpl-3.0으로 라이센스)를 사용하는 것입니다. 목표는 다음과 같습니다.

  • JavaScript ArrayBuffer 인터페이스를 기반으로 문자열에 대한 C와 같은 인터페이스 (즉, 문자 코드 배열-JavaScript의 ArrayBufferView)를 작성
  • StringView.prototype 객체에 메소드를 추가하여 누구나 확장 할 수있는 확장 성이 뛰어난 라이브러리를 만드는 방법
  • 불변의 새로운 JavaScript 캐릭터 라인을 생성하는 것이 아니라, 숫자의 배열로 엄격하게 동작하는 캐릭터 라인과 같은 객체에 대한 메소드의 콜렉션을 작성하는 (지금부터는 stringViews)
  • JavaScript의 기본 UTF-16 DOMString 이외의 유니 코드 인코딩 작업

훨씬 더 많은 유연성을 제공합니다. 그러나 최신 브라우저에 TextEncoder/ TextDecoder가 내장되어있는 동안이 라이브러리에 링크하거나 내장해야 합니다.

지원하다

2018 년 7 월 기준 :

TextEncoder (실험, 표준 트랙)

 Chrome    | Edge      | Firefox   | IE        | Opera     | Safari
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |    19°    |     -     |     25    |     -

 Chrome/A  | Edge/mob  | Firefox/A | Opera/A   |Safari/iOS | Webview/A
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |    19°    |     ?     |     -     |     38

°) 18: Firefox 18 implemented an earlier and slightly different version
of the specification.

WEB WORKER SUPPORT:

Experimental, On Standard Track

 Chrome    | Edge      | Firefox   | IE        | Opera     | Safari
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |     20    |     -     |     25    |     -

 Chrome/A  | Edge/mob  | Firefox/A | Opera/A   |Safari/iOS | Webview/A
 ----------|-----------|-----------|-----------|-----------|-----------
     38    |     ?     |     20    |     ?     |     -     |     38

Data from MDN - `npm i -g mdncomp` by epistemex

2
IE & 가장자리에서 TextDecoder에 대한 지원 없음 : caniuse.com/#search=TextDecoder
안드레이 데미안 - Fekete


: 2018년 4월 18일에서 사파리 모바일 (IOS)에 대한 지원하지 않습니다 developer.mozilla.org/en-US/docs/Web/API/TextDecoder
청동 남자

원 라이너 : var encoder = 'TextEncoder' in window ? new TextEncoder() : {encode: function(str){return Uint8Array.from(str, function(c){return c.codePointAt(0);});}};그렇게하시면됩니다var array = encoder.encode('hello');
Yeti

1
문제 TextEncoder는 문자열에 이진 데이터 (예 : 이미지)가있는 경우 TextEncoder(명확하게) 사용하고 싶지 않다는 것입니다. 코드 포인트가 127보다 큰 문자는 2 바이트를 생성합니다. 문자열에 이진 데이터가있는 이유는 무엇입니까? cy.fixture(NAME, 'binary')( cypress)는 문자열을 생성합니다.
x-yuri

176

Blob / FileReader를 사용하는 Dennis 및 gengkev 솔루션이 작동하지만 해당 접근법을 사용하는 것은 권장하지 않습니다. 간단한 문제에 대한 비동기 접근 방식이며 직접 솔루션보다 훨씬 느립니다. 더 간단하고 훨씬 빠른 솔루션으로 html5rocks에 게시물을 작성했습니다 .http : //updates.html5rocks.com/2012/06/How-to-convert-ArrayBuffer-to-and-from-String

해결책은 다음과 같습니다.

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}

function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

편집하다:

인코딩 API는 문자열 변환 해결하는 데 도움이 문제를. Html5Rocks.com의 Jeff Posnik 이 위의 원본 기사에 대한 답변을 확인 하십시오.

발췌 :

인코딩 API를 사용하면 작업해야하는 많은 표준 인코딩에 관계없이 원시 바이트와 기본 JavaScript 문자열간에 간단하게 변환 할 수 있습니다.

<pre id="results"></pre>

<script>
  if ('TextDecoder' in window) {
    // The local files to be fetched, mapped to the encoding that they're using.
    var filesToEncoding = {
      'utf8.bin': 'utf-8',
      'utf16le.bin': 'utf-16le',
      'macintosh.bin': 'macintosh'
    };

    Object.keys(filesToEncoding).forEach(function(file) {
      fetchAndDecode(file, filesToEncoding[file]);
    });
  } else {
    document.querySelector('#results').textContent = 'Your browser does not support the Encoding API.'
  }

  // Use XHR to fetch `file` and interpret its contents as being encoded with `encoding`.
  function fetchAndDecode(file, encoding) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', file);
    // Using 'arraybuffer' as the responseType ensures that the raw data is returned,
    // rather than letting XMLHttpRequest decode the data first.
    xhr.responseType = 'arraybuffer';
    xhr.onload = function() {
      if (this.status == 200) {
        // The decode() method takes a DataView as a parameter, which is a wrapper on top of the ArrayBuffer.
        var dataView = new DataView(this.response);
        // The TextDecoder interface is documented at http://encoding.spec.whatwg.org/#interface-textdecoder
        var decoder = new TextDecoder(encoding);
        var decodedString = decoder.decode(dataView);
        // Add the decoded file's text to the <pre> element on the page.
        document.querySelector('#results').textContent += decodedString + '\n';
      } else {
        console.error('Error while requesting', file, this);
      }
    };
    xhr.send();
  }
</script>

16
불행히도 html5rocks에 대한 내 의견은 아직 승인되지 않았습니다. 따라서 짧은 대답입니다. 나는 아직도 많은 문자를 그리워하기 때문에 이것이 올바른 방법이 아니라고 생각합니다. 특히 오늘날 대부분의 페이지가 UTF-8로 인코딩되어 있기 때문입니다. 한편으로, 더 특수한 문자 (아시아라고합시다)의 경우 charCodeAt 함수는 4 바이트 값을 반환하므로 잘립니다. 반면 간단한 영어 문자는 ArrayBuffer를 두 번 증가시킵니다 (1 바이트 문자마다 2 바이트를 사용함). WebSocket을 통해 영어 텍스트를 전송한다고 가정하면 두 배의 시간이 필요합니다 (실시간 환경에서는 좋지 않음).
데니스

9
세 가지 예 : (1) This is a cool text!UTF8의 20 바이트-유니 코드의 40 바이트. (2) ÄÖÜUTF8의 6 바이트-유니 코드의 6 바이트 (3) ☐☑☒UTF8의 9 바이트-유니 코드의 6 바이트 문자열을 Blob 및 File Writer API를 통해 UTF8 파일로 저장하려는 경우 ArrayBuffer는 UTF8이 아닌 유니 코드로 작성되므로이 두 가지 방법을 사용할 수 없습니다.
데니스

3
오류가 발생했습니다 : 잡히지 않은 RangeError : 최대 호출 스택 크기를 초과했습니다. 무엇이 문제 일 수 있습니까?
Jacob

6
@Dennis-JS 문자열은 UTF8 (또는 UTF16)이 아닌 UCS2를 사용합니다. 즉 charCodeAt ()는 항상 0-> 65535의 값을 반환합니다. 4 바이트의 끝이 필요한 UTF-8 코드 포인트는 서로 게이트 쌍으로 표시됩니다 ( en.wikipedia 참조). .org / wiki /… )-즉 두 개의 개별 16 비트 UCS2 값.
broofa

6
@jacob-apply () 메서드에 전달할 수있는 배열의 길이에 제한이 있기 때문에 오류가 있다고 생각합니다. 예를 들어 String.fromCharCode.apply(null, new Uint16Array(new ArrayBuffer(246300))).lengthChrome에서 작동하지만 대신 246301을 사용하면 RangeError 예외가 발생합니다
broofa

71

당신은 사용할 수 있습니다 TextEncoderTextDecoder로부터 인코딩 표준 에 의해 polyfilled되고, stringencoding 라이브러리 변환 문자열, 및 ArrayBuffers에서 :

var uint8array = new TextEncoder().encode(string);
var string = new TextDecoder(encoding).decode(uint8array);

2
그건 그렇고, 기본적으로 Firefox에서 사용할 수 있습니다 : developer.mozilla.org/en-US/docs/Web/API/TextDecoder.decode
Joel Richard

2
이상한 해결 방법보다 훨씬 나은 새로운 API를 추천합니다!
Tomáš Zato-복원 모니카

1
모든 유형의 문자에는 적용되지 않습니다.
David

5
npm install text-encoding, var textEncoding = require('text-encoding'); var TextDecoder = textEncoding.TextDecoder;. 고맙지 만 사양 할게.
Evan Hu

grumble ... 기존 배열 버퍼가있는 경우 문자열을 작성하고 싶습니다 .uint8array를 가져 와서 두 번째로 복사해야한다고 생각하십니까 ??
shaunc

40

얼룩이보다 느리다 String.fromCharCode(null,array);

그러나 배열 버퍼가 너무 커지면 실패합니다. 내가 찾은 최선의 해결책 String.fromCharCode(null,array);은 스택을 날려 버리지 않지만 한 번에 하나의 문자보다 빠른 작업 으로 사용 하고 분할하는 것입니다.

대형 배열 버퍼에 가장 적합한 솔루션은 다음과 같습니다.

function arrayBufferToString(buffer){

    var bufView = new Uint16Array(buffer);
    var length = bufView.length;
    var result = '';
    var addition = Math.pow(2,16)-1;

    for(var i = 0;i<length;i+=addition){

        if(i + addition > length){
            addition = length - i;
        }
        result += String.fromCharCode.apply(null, bufView.subarray(i,i+addition));
    }

    return result;

}

나는 이것을 블롭을 사용하는 것보다 약 20 배 빠릅니다. 또한 100MB 이상의 큰 문자열에도 작동합니다.


3
이 솔루션을 사용해야합니다. 이것은 허용 된 것보다 하나 더 많은 사용 사례를 해결하기 때문에
sam

24

gengkev의 답변을 바탕으로 BlobBuilder 가 String 및 ArrayBuffer를 처리 할 수 ​​있으므로 두 가지 방법으로 함수를 만들었습니다 .

function string2ArrayBuffer(string, callback) {
    var bb = new BlobBuilder();
    bb.append(string);
    var f = new FileReader();
    f.onload = function(e) {
        callback(e.target.result);
    }
    f.readAsArrayBuffer(bb.getBlob());
}

function arrayBuffer2String(buf, callback) {
    var bb = new BlobBuilder();
    bb.append(buf);
    var f = new FileReader();
    f.onload = function(e) {
        callback(e.target.result)
    }
    f.readAsText(bb.getBlob());
}

간단한 테스트 :

string2ArrayBuffer("abc",
    function (buf) {
        var uInt8 = new Uint8Array(buf);
        console.log(uInt8); // Returns `Uint8Array { 0=97, 1=98, 2=99}`

        arrayBuffer2String(buf, 
            function (string) {
                console.log(string); // returns "abc"
            }
        )
    }
)

arrayBuffer2String ()에서 console.log () 대신 callback (...)을 호출한다는 의미입니까? 그렇지 않으면 콜백 인수가 사용되지 않습니다.
Dan Phillimore

genkev와 Dennis에게 감사의 말을 전합니다. 이것을 달성하기위한 동기식 방법이 없다는 것은 어리석은 것 같지만, 무엇을 할 수
있을까

JavaScript는 단일 스레드입니다. 따라서 FileReader는 두 가지 이유로 비 동기화됩니다. (1) (거대한) 파일을로드하는 동안 다른 JavaScript의 실행을 차단하지 않으며 (더 복잡한 응용 프로그램을 상상) 2) UI / 브라우저를 차단하지 않습니다 (일반적인 문제) 긴 실행 JS 코드로). 많은 API가 비동기식입니다. XMLHttpRequest 2에서도 동기식이 제거됩니다.
Dennis

실제로 이것이 효과가 있기를 바랐지만 문자열에서 ArrayBuffer 로의 변환이 안정적으로 작동하지 않습니다. 256 값의 ArrayBuffer를 만들고 길이가 256 인 문자열로 바꿀 수 있습니다.하지만 초기 ArrayBuffer의 내용에 따라 ArrayBuffer로 다시 변환하려고하면 376 개의 요소가 나옵니다. 내 문제를 재현하려는 경우 Uint8Array에서 ArrayBuffer를 16x16 그리드로 처리 a[y * w + x] = (x + y) / 2 * 16; 하려고 시도했지만 getBlob("x")많은 다른 mimetype을 사용하여 시도한 대로 계산 된 값 이 있습니다 -운이 없습니다.
Matt Cruikshank

18
최신 브라우저에서는 BlobBuilder가 더 이상 사용되지 않습니다. 변경 new BlobBuilder(); bb.append(buf);하려면 new Blob([buf]),를 통해 UintArray에 두 번째 함수에서 ArrayBuffer 캐스트 new UintArray(buf)(또는 기본 데이터 유형에 적합한의 무엇이든), 다음 제거 getBlob()를 호출합니다. 마지막으로 청결을 위해 bb는 더 이상 BlobBuilder가 아니기 때문에 bb로 이름을 바꿉니다.
sowbug 2018 년

18

다음은 배열 버퍼에서 이진 문자열을 가져 오는 것에 관한 것입니다.

사용하지 않는 것이 좋습니다

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

그것 때문에

  1. 큰 버퍼에서 충돌 (누군가 246300의 "마법"크기에 대해 썼지 만 Maximum call stack size exceeded120000 바이트 버퍼에서 오류 가 발생했습니다 (Chrome 29))
  2. 그것은이 정말 성능 저하 (아래 참조)

동기식 솔루션이 정확히 필요한 경우 다음과 같은 것을 사용하십시오.

var
  binaryString = '',
  bytes = new Uint8Array(arrayBuffer),
  length = bytes.length;
for (var i = 0; i < length; i++) {
  binaryString += String.fromCharCode(bytes[i]);
}

이전보다 느리지 만 올바르게 작동합니다. 이것을 작성하는 순간 그 문제에 대한 매우 빠른 동기 솔루션이없는 것 같습니다 (이 주제에서 언급 된 모든 라이브러리는 동기 기능에 대해 동일한 접근 방식을 사용합니다).

하지만 내가 정말로 권장하는 것은 Blob+ FileReader접근법을 사용 하는 것입니다.

function readBinaryStringFromArrayBuffer (arrayBuffer, onSuccess, onFail) {
  var reader = new FileReader();
  reader.onload = function (event) {
    onSuccess(event.target.result);
  };
  reader.onerror = function (event) {
    onFail(event.target.error);
  };
  reader.readAsBinaryString(new Blob([ arrayBuffer ],
    { type: 'application/octet-stream' }));
}

유일한 단점은 (전부가 아님) 그것이 비동기 적이라는 것입니다 . 그리고 이전 솔루션 보다8-10 배 빠릅니다 ! (일부 세부 정보 : 내 환경의 동기 솔루션은 2.4Mb 버퍼의 경우 950-1050ms가 걸렸지 만 FileReader 솔루션은 동일한 양의 데이터에 대해 약 100-120ms의 시간이 걸렸습니다 .100Kb 버퍼에서 동기 솔루션을 모두 테스트 했으며 거의 동시에, 따라서 '적용'을 사용하면 루프가 훨씬 느리지 않습니다.)

BTW here : ArrayBuffer와 String author 를 변환하는 방법은 나와 같은 두 가지 접근법을 비교하고 완전히 반대의 결과를 얻습니다 ( 그의 테스트 코드는 여기에 있습니다 ) 왜 그렇게 다른 결과가 있습니까? 아마도 1Kb 길이의 테스트 문자열 ( "veryLongStr"이라고 함) 때문일 수 있습니다. 버퍼는 2.4Mb 크기의 JPEG 이미지였습니다.


13

( 업데이트 더 나은 솔루션을 제공 한이 답변의 후반부를 참조하십시오.)

또한이 문제에 부딪 쳤습니다 .FF 6 (한 방향)에서 다음이 작동합니다.

var buf = new ArrayBuffer( 10 );
var view = new Uint8Array( buf );
view[ 3 ] = 4;
alert(Array.prototype.slice.call(view).join(""));

불행히도 물론 문자가 아닌 배열 값의 ASCII 텍스트 표현으로 끝납니다. 그래도 루프보다 훨씬 더 효율적이어야합니다. 예. 위의 예에서 결과는 0004000000여러 개의 null 문자 및 chr (4)가 아니라입니다.

편집하다:

에보고 한 후 MDC 여기 , 당신은을 만들 수 있습니다 ArrayBuffer에서 Array다음과 같이 :

var arr = new Array(23);
// New Uint8Array() converts the Array elements
//  to Uint8s & creates a new ArrayBuffer
//  to store them in & a corresponding view.
//  To get at the generated ArrayBuffer,
//  you can then access it as below, with the .buffer property
var buf = new Uint8Array( arr ).buffer;

원래 질문에 대답하기 위해 ArrayBuffer<-> String를 다음과 같이 변환 할 수 있습니다 .

var buf, view, str;
buf = new ArrayBuffer( 256 );
view = new Uint8Array( buf );

view[ 0 ] = 7; // Some dummy values
view[ 2 ] = 4;

// ...

// 1. Buffer -> String (as byte array "list")
str = bufferToString(buf);
alert(str); // Alerts "7,0,4,..."

// 1. String (as byte array) -> Buffer    
buf = stringToBuffer(str);
alert(new Uint8Array( buf )[ 2 ]); // Alerts "4"

// Converts any ArrayBuffer to a string
//  (a comma-separated list of ASCII ordinals,
//  NOT a string of characters from the ordinals
//  in the buffer elements)
function bufferToString( buf ) {
    var view = new Uint8Array( buf );
    return Array.prototype.join.call(view, ",");
}
// Converts a comma-separated ASCII ordinal string list
//  back to an ArrayBuffer (see note for bufferToString())
function stringToBuffer( str ) {
    var arr = str.split(",")
      , view = new Uint8Array( arr );
    return view.buffer;
}

편의를 위해 다음은 function원시 유니 코드 String를 로 변환 하기위한 ArrayBuffer것입니다 (ASCII / 1 바이트 문자로만 작동 함)

function rawStringToBuffer( str ) {
    var idx, len = str.length, arr = new Array( len );
    for ( idx = 0 ; idx < len ; ++idx ) {
        arr[ idx ] = str.charCodeAt(idx) & 0xFF;
    }
    // You may create an ArrayBuffer from a standard array (of values) as follows:
    return new Uint8Array( arr ).buffer;
}

// Alerts "97"
alert(new Uint8Array( rawStringToBuffer("abc") )[ 0 ]);

위의 예에서는 문자열을 예를 들어 저장할 수있는 ArrayBuffer-> String및 다시 다시 갈 ArrayBuffer수 있습니다. .localStorage:)

도움이 되었기를 바랍니다,


1
나는 이것이 시간이나 공간면에서 효율적인 방법이라고 생각하지 않으며, 이것은 이진 데이터를 저장하는 매우 특이한 방법입니다.
kpozin 2016 년

@kpozin : 내가 아는 한, localStorage에 이진 데이터를 저장하는 다른 방법은 없습니다
Dan Phillimore

1
base64 인코딩을 사용하는 것은 어떻습니까?
Nick Sotiros

13

여기의 솔루션과 달리 UTF-8 데이터와의 변환이 필요했습니다. 이를 위해 (un) escape / (en) decodeURIComponent 트릭을 사용하여 다음 두 함수를 코딩했습니다. gc로 복구해야하지만 인코딩 된 utf8- 문자열 길이의 9 배를 할당하는 것은 상당히 낭비입니다. 100MB 텍스트에는 사용하지 마십시오.

function utf8AbFromStr(str) {
    var strUtf8 = unescape(encodeURIComponent(str));
    var ab = new Uint8Array(strUtf8.length);
    for (var i = 0; i < strUtf8.length; i++) {
        ab[i] = strUtf8.charCodeAt(i);
    }
    return ab;
}

function strFromUtf8Ab(ab) {
    return decodeURIComponent(escape(String.fromCharCode.apply(null, ab)));
}

작동하는지 확인 :

strFromUtf8Ab(utf8AbFromStr('latinкирилицаαβγδεζηあいうえお'))
-> "latinкирилицаαβγδεζηあいうえお"

8

문자열에 이진 데이터가있는 경우 ( nodejs+ readFile(..., 'binary')또는 cypress+ cy.fixture(..., 'binary')등에서 얻은 )를 사용할 수 없습니다 TextEncoder. 지원합니다 utf8. 값 >= 128이있는 바이트 는 각각 2 바이트로 바뀝니다.

ES2015 :

a = Uint8Array.from(s, x => x.charCodeAt(0))

Uint8Array (33) [2, 134, 140, 186, 82, 70, 108, 182, 233, 40, 143, 247, 29, 76, 245, 206, 29, 87, 48, 160, 78, 225, 242 , 56, 236, 201, 80, 80, 152, 118, 92, 144, 48

s = String.fromCharCode.apply(null, a)

"ºRFl¶é (÷ LõÎW0 Náò8ìÉPPv \ 0"


7

기본적으로 출력을 파일에 쓰려고하는데 제대로 인코딩되지 않았기 때문에이 접근법에 문제가 있음을 발견했습니다. JS가 UCS-2 인코딩 ( source , source ) 을 사용하는 것처럼 보이기 때문에이 솔루션을 한 단계 더 확장해야합니다.

나는 일반 텍스트에 어려움이 없었지만 아랍이나 한국어로 내려 갔을 때 출력 파일에 모든 문자가 없었지만 대신 오류 문자가 표시되었습니다

파일 출력 : ","10k unit":"",Follow:"Õ©íüY‹","Follow %{screen_name}":"%{screen_name}U“’Õ©íü",Tweet:"ĤüÈ","Tweet %{hashtag}":"%{hashtag} ’ĤüÈY‹","Tweet to %{name}":"%{name}U“xĤüÈY‹"},ko:{"%{followers_count} followers":"%{followers_count}…X \Ì","100K+":"100Ì tÁ","10k unit":"Ì è",Follow:"\°","Follow %{screen_name}":"%{screen_name} Ø \°X0",K:"œ",M:"1Ì",Tweet:"¸","Tweet %{hashtag}":"%{hashtag}

실물: ","10k unit":"万",Follow:"フォローする","Follow %{screen_name}":"%{screen_name}さんをフォロー",Tweet:"ツイート","Tweet %{hashtag}":"%{hashtag} をツイートする","Tweet to %{name}":"%{name}さんへツイートする"},ko:{"%{followers_count} followers":"%{followers_count}명의 팔로워","100K+":"100만 이상","10k unit":"만 단위",Follow:"팔로우","Follow %{screen_name}":"%{screen_name} 님 팔로우하기",K:"천",M:"백만",Tweet:"트윗","Tweet %{hashtag}":"%{hashtag}

나는의 정보했다 데니스 '솔루션이 게시물에 내가 발견합니다.

내 코드는 다음과 같습니다.

function encode_utf8(s) {
  return unescape(encodeURIComponent(s));
}

function decode_utf8(s) {
  return decodeURIComponent(escape(s));
}

 function ab2str(buf) {
   var s = String.fromCharCode.apply(null, new Uint8Array(buf));
   return decode_utf8(decode_utf8(s))
 }

function str2ab(str) {
   var s = encode_utf8(str)
   var buf = new ArrayBuffer(s.length); 
   var bufView = new Uint8Array(buf);
   for (var i=0, strLen=s.length; i<strLen; i++) {
     bufView[i] = s.charCodeAt(i);
   }
   return bufView;
 }

이를 통해 인코딩 문제없이 파일에 내용을 저장할 수 있습니다.

작동 방식 : 기본적으로 UTF-8 문자를 구성하는 단일 8 바이트 청크를 가져와 단일 문자로 저장합니다 (따라서 이러한 방식으로 작성된 UTF-8 문자는 이러한 문자 중 1-4 개로 구성 될 수 있음). UTF-8은 길이가 1-4 바이트 인 형식으로 문자를 인코딩합니다. 우리가 여기서하는 일은 URI 컴포넌트에서 찌르기를 인코딩 한 다음이 컴포넌트를 가져와 해당 8 바이트 문자로 변환하는 것입니다. 이런 식으로 1 바이트 이상의 UTF8 문자로 제공되는 정보를 잃지 않습니다.


6

거대한 배열 예제를 사용 arr.length=1000000 하면 스택 콜백 문제를 피하기 위해이 코드를 사용할 수 있습니다

function ab2str(buf) {
var bufView = new Uint16Array(buf);
var unis =""
for (var i = 0; i < bufView.length; i++) {
    unis=unis+String.fromCharCode(bufView[i]);
}
return unis
}

위에서 역 기능 mangini 답변

function str2ab(str) {
    var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
    var bufView = new Uint16Array(buf);
    for (var i=0, strLen=str.length; i<strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

4

글쎄, 여기에 똑같은 일을하는 다소 복잡한 방법이 있습니다.

var string = "Blah blah blah", output;
var bb = new (window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder)();
bb.append(string);
var f = new FileReader();
f.onload = function(e) {
  // do whatever
  output = e.target.result;
}
f.readAsArrayBuffer(bb.getBlob());

편집 : BlobBuilder는 오랫동안이 게시물을 쓸 때 존재하지 않는 Blob 생성자를 위해 오래 사용되지 않았습니다. 다음은 업데이트 된 버전입니다. (그렇습니다. 이것은 항상 변환을 수행하는 매우 어리석은 방법이었습니다. 그러나 그것은 단지 재미를위한 것입니다!)

var string = "Blah blah blah", output;
var f = new FileReader();
f.onload = function(e) {
  // do whatever
  output = e.target.result;
};
f.readAsArrayBuffer(new Blob([string]));

3

에서 변환 mangini의 솔루션을 가지고 노는 후 ArrayBufferString- ab2str(! 내가 발견 한 가장 우아하고 유용 하나입니다 - 감사) 큰 배열을 처리 할 때, 나는 몇 가지 문제가 있었다. 보다 구체적으로 호출 String.fromCharCode.apply(null, new Uint16Array(buf));하면 오류가 발생합니다.

arguments array passed to Function.prototype.apply is too large.

그것을 해결하기 위해 (바이 패스) 입력 ArrayBuffer을 청크 로 처리하기로 결정했습니다 . 따라서 수정 된 솔루션은 다음과 같습니다.

function ab2str(buf) {
   var str = "";
   var ab = new Uint16Array(buf);
   var abLen = ab.length;
   var CHUNK_SIZE = Math.pow(2, 16);
   var offset, len, subab;
   for (offset = 0; offset < abLen; offset += CHUNK_SIZE) {
      len = Math.min(CHUNK_SIZE, abLen-offset);
      subab = ab.subarray(offset, offset+len);
      str += String.fromCharCode.apply(null, subab);
   }
   return str;
}

청크 크기는 2^16개발 환경에서 작동하는 크기이기 때문에 설정되었습니다 . 더 높은 값을 설정하면 동일한 오류가 다시 발생했습니다. CHUNK_SIZE변수를 다른 값 으로 설정하여 변경할 수 있습니다 . 짝수를 갖는 것이 중요합니다.

성능에 대한 참고 사항-이 솔루션에 대한 성능 테스트를 수행하지 않았습니다. 그러나 이전 솔루션을 기반으로하고 대형 배열을 처리 할 수 ​​있으므로 사용하지 않는 이유는 없습니다.


typedarray.subarray 를 사용 하여 지정된 위치와 크기에서 청크를 얻을 수 있습니다 . 이것은 js에서 이진 형식의 헤더를 읽는 것입니다
Nikos M.


2
  stringToArrayBuffer(byteString) {
    var byteArray = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
      byteArray[i] = byteString.codePointAt(i);
    }
    return byteArray;
  }
  arrayBufferToString(buffer) {
    var byteArray = new Uint8Array(buffer);
    var byteString = '';
    for (var i = 0; i < byteArray.byteLength; i++) {
      byteString += String.fromCodePoint(byteArray[i]);
    }
    return byteString;
  }

문자열에 유니 코드 문자가 포함되어 있으면이 코드는 버그가 있습니다. 예 :arrayBufferToString(stringToArrayBuffer('🐴'))==='44'
xmcp

2

node.js 및 https://github.com/feross/buffer를 사용하는 브라우저

function ab2str(buf: Uint8Array) {
  return Buffer.from(buf).toString('base64');
}
function str2ab(str: string) {
  return new Uint8Array(Buffer.from(str, 'base64'))
}

참고 : 여기의 솔루션은 효과가 없었습니다. node.js와 브라우저를 지원하고 UInt8Array를 문자열로 직렬화해야합니다. 숫자 []로 직렬화 할 수 있지만 불필요한 공간을 차지합니다. 이 솔루션을 사용하면 base64이므로 인코딩에 대해 걱정할 필요가 없습니다. 다른 사람들이 같은 문제로 어려움을 겪을 경우를 대비해서 ... 내 두 센트


2

arrayBuffer binaryStr이 있다고 가정 해 보겠습니다.

let text = String.fromCharCode.apply(null, new Uint8Array(binaryStr));

그런 다음 텍스트를 상태에 할당합니다.


1

atob ()이 반환하는 "기본"이진 문자열은 문자 당 1 바이트 배열입니다.

따라서 문자에 2 바이트를 저장해서는 안됩니다.

var arrayBufferToString = function(buffer) {
  return String.fromCharCode.apply(null, new Uint8Array(buffer));
}

var stringToArrayBuffer = function(str) {
  return (new Uint8Array([].map.call(str,function(x){return x.charCodeAt(0)}))).buffer;
}

1

예:

const encstr = (`TextEncoder` in window) ? new TextEncoder().encode(str) : Uint8Array.from(str, c => c.codePointAt(0));

0

BlobBuilder와 같은 더 이상 사용되지 않는 API를 사용하지 않는 것이 좋습니다.

BlobBuilder는 Blob 객체에 의해 오랫동안 사용되지 않습니다. BlobBuilder가 사용되는 Dennis의 답변 코드를 아래 코드와 비교하십시오.

function arrayBufferGen(str, cb) {

  var b = new Blob([str]);
  var f = new FileReader();

  f.onload = function(e) {
    cb(e.target.result);
  }

  f.readAsArrayBuffer(b);

}

이것은 더 이상 사용되지 않는 방법과 비교하여 얼마나 깨끗하고 부풀어 오른 지 주목하십시오 ... 그렇습니다. 여기서 고려해야 할 사항입니다.


예, 그러나 Blob 생성자는 2012 년에 실제로 다시 사용할 수 없었습니다.)
gengkev


0

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

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