Converting between strings and ArrayBuffers

后端 未结 24 871
慢半拍i
慢半拍i 2020-11-22 04:50

Is there a commonly accepted technique for efficiently converting JavaScript strings to ArrayBuffers and vice-versa? Specifically, I\'d like to be able to write the contents

相关标签:
24条回答
  • 2020-11-22 05:23

    Although Dennis and gengkev solutions of using Blob/FileReader work, I wouldn't suggest taking that approach. It is an async approach to a simple problem, and it is much slower than a direct solution. I've made a post in html5rocks with a simpler and (much faster) solution: http://updates.html5rocks.com/2012/06/How-to-convert-ArrayBuffer-to-and-from-String

    And the solution is:

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

    EDIT:

    The Encoding API helps solving the string conversion problem. Check out the response from Jeff Posnik on Html5Rocks.com to the above original article.

    Excerpt:

    The Encoding API makes it simple to translate between raw bytes and native JavaScript strings, regardless of which of the many standard encodings you need to work with.

    <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>
    
    0 讨论(0)
  • 2020-11-22 05:24
    var decoder = new TextDecoder ();
    var string = decoder.decode (arrayBuffer);
    

    See https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/decode

    0 讨论(0)
  • 2020-11-22 05:25

    (Update Please see the 2nd half of this answer, where I have (hopefully) provided a more complete solution.)

    I also ran into this issue, the following works for me in FF 6 (for one direction):

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

    Unfortunately, of course, you end up with ASCII text representations of the values in the array, rather than characters. It still (should be) much more efficient than a loop, though. eg. For the example above, the result is 0004000000, rather than several null chars & a chr(4).

    Edit:

    After looking on MDC here, you may create an ArrayBuffer from an Array as follows:

    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;
    

    To answer your original question, this allows you to convert ArrayBuffer <-> String as follows:

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

    For convenience, here is a function for converting a raw Unicode String to an ArrayBuffer (will only work with ASCII/one-byte characters)

    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 ]);
    

    The above allow you to go from ArrayBuffer -> String & back to ArrayBuffer again, where the string may be stored in eg. .localStorage :)

    Hope this helps,

    Dan

    0 讨论(0)
  • 2020-11-22 05:26

    Let's say you have an arrayBuffer binaryStr:

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

    and then you assign the text to the state.

    0 讨论(0)
  • 2020-11-22 05:26

    I used this and works for me.

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 05:27

    if you used huge array example arr.length=1000000 you can this code to avoid stack callback problems

    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
    }
    

    reverse function mangini answer from top

    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;
    }
    
    0 讨论(0)
提交回复
热议问题