28

What is the way to obtain binary string from ArrayBuffer in JavaScript?

I don't want to encode the bytes, just get the binary representation as String.

Thanks in advance!

1
  • 1
    I don't fully understand what conversion you are actually trying to accomplish, can you give some further explanation to clarify what you want? Commented May 3, 2013 at 17:54

6 Answers 6

19

The following code will consistently convert an ArrayBuffer to a String and back again without losing or adding any additional bytes.

function ArrayBufferToString(buffer) {
    return BinaryToString(String.fromCharCode.apply(null, Array.prototype.slice.apply(new Uint8Array(buffer))));
}

function StringToArrayBuffer(string) {
    return StringToUint8Array(string).buffer;
}

function BinaryToString(binary) {
    var error;

    try {
        return decodeURIComponent(escape(binary));
    } catch (_error) {
        error = _error;
        if (error instanceof URIError) {
            return binary;
        } else {
            throw error;
        }
    }
}

function StringToBinary(string) {
    var chars, code, i, isUCS2, len, _i;

    len = string.length;
    chars = [];
    isUCS2 = false;
    for (i = _i = 0; 0 <= len ? _i < len : _i > len; i = 0 <= len ? ++_i : --_i) {
        code = String.prototype.charCodeAt.call(string, i);
        if (code > 255) {
            isUCS2 = true;
            chars = null;
            break;
        } else {
            chars.push(code);
        }
    }
    if (isUCS2 === true) {
        return unescape(encodeURIComponent(string));
    } else {
        return String.fromCharCode.apply(null, Array.prototype.slice.apply(chars));
    }
}

function StringToUint8Array(string) {
    var binary, binLen, buffer, chars, i, _i;
    binary = StringToBinary(string);
    binLen = binary.length;
    buffer = new ArrayBuffer(binLen);
    chars  = new Uint8Array(buffer);
    for (i = _i = 0; 0 <= binLen ? _i < binLen : _i > binLen; i = 0 <= binLen ? ++_i : --_i) {
        chars[i] = String.prototype.charCodeAt.call(binary, i);
    }
    return chars;
}

I tested it by round-tripping the following values in this jsfiddle: http://jsfiddle.net/potatosalad/jrdLV/

(String) "abc" -> (ArrayBuffer) -> (String) "abc"
(String) "aΩc" -> (ArrayBuffer) -> (String) "aΩc"
(Uint8Array) [0,1,255] -> (ArrayBuffer) -> (String) -> (Uint8Array) [0,1,255]
(Uint16Array) [0,1,256,65535] -> (ArrayBuffer) -> (String) -> (Uint16Array) [0,1,256,65535]
(Uint32Array) [0,1,256,65536,4294967295] -> (ArrayBuffer) -> (String) -> (Uint32Array) [0,1,256,65536,4294967295]
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. What encoding it return from fileReader.readAsArrayBuffer and fileReader.readAsBinaryString ?
@aung readAsBinaryString is just a string of 0s and 1s based on conversion of the individual bytes to those. There's no "encoding". readAsArrayBuffer uses whatever mask you tell it (i.e. Uint8, Uint16, Uint32, etc.).
ArrayBufferToString() doesn't seem to convert an ArrayBuffer / Uint8Array correctly to a binary string. Testing with a PNG file and some bytes are added, some are changed. Most are correct, however. Do I something wrong? I read the PNG file with FileReader.readAsArrayBuffer() and then sent it to ArrayBufferToString().
16

This has been made much simpler by additions to JavaScript in recent years – here's a one-line method to convert a Uint8Array into a binary-encoded string:

const toBinString = (bytes) =>
  bytes.reduce((str, byte) => str + byte.toString(2).padStart(8, '0'), '');

Example:

console.log(toBinString(Uint8Array.from([42, 100, 255, 0])))
// => '00101010011001001111111100000000'

If you're starting with an ArrayBuffer, create a Uint8Array "view" of the buffer to pass into this method:

const view = new Uint8Array(myArrayBuffer);
console.log(toBinString(view));

Source: the Libauth library (binToBinString method)

Comments

3

This will give you a binary string from a typed array

var bitsPerByte = 8;
var array = new Uint8Array([0, 50, 100, 170, 200, 255]);
var string = "";

function repeat(str, num) {
    if (str.length === 0 || num <= 1) {
        if (num === 1) {
            return str;
        }

        return '';
    }

    var result = '',
        pattern = str;

    while (num > 0) {
        if (num & 1) {
            result += pattern;
        }

        num >>= 1;
        pattern += pattern;
    }

    return result;
}

function lpad(obj, str, num) {
    return repeat(str, num - obj.length) + obj;
}

Array.prototype.forEach.call(array, function (element) {
    string += lpad(element.toString(2), "0", bitsPerByte);
});

console.log(string);

Output is

000000000011001001100100101010101100100011111111

On jsfiddle

Or perhaps you are asking about this?

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

Note: that using apply in this manner means that you can hit the argument limitation (some 16000 elements or so), and then you will have to loop through the array elements instead.

On html5rocks

1 Comment

some explanation of what code is doing seems to be granted here
3

I realize this is a very old question, but I wanted to add one more possible case/solution since I landed on this from a search:

I wanted an async/await version of FileReader.readAsBinaryString() because I am a capricious person and the callback interface annoyed me:

// Suppose `file` exists

let fr = new FileReader()
let string1

fr.onload = ({ target: { result }}) => string1 = result
fr.readAsBinaryString(file)

console.log(string1)

Additionally, MDN says that FileReader.readAsBinaryString() only exists for backward compatibility, and FileReader.readAsArrayBuffer() is recommended instead.

There are new methods available on Blob/File that give you text, ArrayBuffers, and streams, but no binary strings. Heeding MDN's advice, I figured we could go from ArrayBuffer to binary string using the new methods, and indeed we can:

// Again, suppose `file` exists

let ab, bufferToString, string2

bufferToString = (buffer) => {
    const bytes = new Uint8Array(buffer)
    return bytes.reduce((string, byte) => (string + String.fromCharCode(byte)), "")
}

ab = await file.arrayBuffer()
string2 = bufferToString(ab)

console.log(string2)

Assuming this is done in the same browser console:

string1 === string2 // true

Whether this is intelligence or stupidity is left to the reader.

2 Comments

Note that readAsBinaryString is now deprecated.
@EduardoProcópioGomez I did note that. It's already in the answer and is literally the entire reason I came to my solution.
0

This code works for me

function arrayBufferToBinary(buffer) {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return binary;
}

Comments

-1
function string2Bin(s) {
  var b = new Array();
  var last = s.length;
  for (var i = 0; i < last; i++) {
    var d = s.charCodeAt(i);
    if (d < 128)
      b[i] = dec2Bin(d);
    else {
      var c = s.charAt(i);
      alert(c + ' is NOT an ASCII character');
      b[i] = -1;
    }
  }
  return b;
}

function dec2Bin(d) {
  var b = '';
  for (var i = 0; i < 8; i++) {
    b = (d%2) + b;
    d = Math.floor(d/2);
  }
  return b;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.