8

This question has received answers in the past, but I would definitely say that it is still not answered.

There is almost documentation on ArrayBuffers in general, let alone on specific applications. I have been researching for days to no avail on this.

Essentially I need to try to convert an ArrayBuffer that I got from a file reader (here: https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsArrayBuffer) to a string, and then convert that string back to the same ArrayBuffer.

I have tried these methods for example

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 b

I get the following error: "byte length of Uint16Array should be a multiple of 2"

I also tried the following

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

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

And received this error: Maximum call stack size exceeded

It seems that there are just no good methods for the following conversions: AB --> String || String -> AB

14
  • Can you show an example input you used? The first code is working fine for lorem ipsum. Commented May 15, 2016 at 3:53
  • I am uploading image file, using filereader to read as arraybuffer and then sending the contents to the ab2str Commented May 15, 2016 at 4:03
  • Maybe the file size is so large, that it causes more call stacks? Commented May 15, 2016 at 4:05
  • Also I should note that I am using PGP encryption on the strings with openpgpjs.org, one thing to note that is I just tried a smaller image file and the methods "worked" (didn't cause any errors), but the image file that came out was still corrupted Commented May 15, 2016 at 4:07
  • 1
    Do you need the ArrayBuffer specifically anyway? Why not use base64? Commented May 15, 2016 at 4:42

3 Answers 3

18

Most browsers now have TextEncoder and TextDecoder, and Node has util.TextEncoder and util.TextDecoder. This WHATWG standard provides straightforward methods to convert between byte arrays (which have a buffer attribute) and strings:

const str = new TextDecoder().decode(byteArray);
const byteArray = new TextEncoder().encode(str);
const buffer = byteArray.buffer;
Sign up to request clarification or add additional context in comments.

3 Comments

This does not construct an ArrayBuffer from a String.
I'm sorry! I forgot to show how to access the buffer! Thanks for pointing that out, @bryc.
Thanks for the helpful edit, @webchitect!
7

There is an asynchronous way using Blob and FileReader.

You can specify any valid encoding.

function arrayBufferToString( buffer, encoding, callback ) {
    var blob = new Blob([buffer],{type:'text/plain'});
    var reader = new FileReader();
    reader.onload = function(evt){callback(evt.target.result);};
    reader.readAsText(blob, encoding);
}

function stringToArrayBuffer( string, encoding, callback ) {
    var blob = new Blob([string],{type:'text/plain;charset='+encoding});
    var reader = new FileReader();
    reader.onload = function(evt){callback(evt.target.result);};
    reader.readAsArrayBuffer(blob);
}


//example:
var buf = new Uint8Array([65,66,67]);
arrayBufferToString(buf, 'UTF-8', console.log.bind(console)); //"ABC"

stringToArrayBuffer('ABC', 'UTF-8', console.log.bind(console)); //[65,66,67]

Comments

3

Complimenting the excellent answer by cuixping, here are the TypeScript versions of the conversion functions

const arrayBufferToString = (buffer: ArrayBuffer, encoding = 'UTF-8'): Promise<string> => {
  return new Promise<string>((resolve, reject) => {
    const blob = new Blob([buffer], { type: 'text/plain' });
    const reader = new FileReader();
    reader.onload = (evt) => {
      if (evt.target) {
        resolve(evt.target.result as string);
      } else {
        reject(new Error('Could not convert array to string!'));
      }
    };
    reader.readAsText(blob, encoding);
  });
};

const stringToArrayBuffer = (text: string, encoding = 'UTF-8'): Promise<ArrayBuffer> => {
  return new Promise<ArrayBuffer>((resolve, reject) => {
    const blob = new Blob([text], { type: `text/plain;charset=${encoding}` });
    const reader = new FileReader();
    reader.onload = (evt) => {
      if (evt.target) {
        resolve(evt.target.result as ArrayBuffer);
      } else {
        reject(new Error('Could not convert string to array!'));
      }
    };
    reader.readAsArrayBuffer(blob);
  });
};

1 Comment

You can initialize a Buffer more simply with Buffer.from("string").

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.