29

In this page http://www.html5rocks.com/en/tutorials/file/dndfiles/ if you scroll down to example "Example: Slicing a file. Try it!" you will see uses of readAsBinaryString API to read bytes of local files.

I've seen IE (My case its IE11) doesn't support readAsBinaryString.

Even this code mentioned in post HTML5 File API read as text and binary breaks at readAsBinaryString in IE11.

I have seen some post in stack overflow, it suggests use of ReadAsArrayBuffer(). But it is also not working. It returns undefined.

My question is what are the options if I have to run it on IE11? Is it possible to write another IE compatible JS function which will do the JOB of readAsBinaryString().

Community
  • 1
  • 1
Dev.K.
  • 2,428
  • 5
  • 35
  • 49

6 Answers6

52

I combine @Jack answer with my comment to show a complete working example.

In the <head> section I added this script to add FileReader.readAsBinaryString function in IE11

if (FileReader.prototype.readAsBinaryString === undefined) {
    FileReader.prototype.readAsBinaryString = function (fileData) {
        var binary = "";
        var pt = this;
        var reader = new FileReader();
        reader.onload = function (e) {
            var bytes = new Uint8Array(reader.result);
            var length = bytes.byteLength;
            for (var i = 0; i < length; i++) {
                binary += String.fromCharCode(bytes[i]);
            }
            //pt.result  - readonly so assign content to another property
            pt.content = binary;
            pt.onload(); // thanks to @Denis comment
        }
        reader.readAsArrayBuffer(fileData);
    }
}

Then I needed to slightly modify my original script code because target.result has no value when using this fallback function.

var reader = new FileReader();
reader.onload = function (e) {
    // ADDED CODE
    if (!e) {
        var data = reader.content;
    }
    else {
        var data = e.target.result;
    }

    // business code
};
reader.readAsBinaryString(myFile);
Naigel
  • 9,086
  • 16
  • 65
  • 106
36

This is my solution.

var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
  if (reader.result) reader.content = reader.result;
  var base64Data = btoa(reader.content);
  //...
}
//extend FileReader
if (!FileReader.prototype.readAsBinaryString) {
    FileReader.prototype.readAsBinaryString = function (fileData) {
       var binary = "";
       var pt = this;
       var reader = new FileReader();      
       reader.onload = function (e) {
           var bytes = new Uint8Array(reader.result);
           var length = bytes.byteLength;
           for (var i = 0; i < length; i++) {
               binary += String.fromCharCode(bytes[i]);
           }
        //pt.result  - readonly so assign binary
        pt.content = binary;
        $(pt).trigger('onload');
    }
    reader.readAsArrayBuffer(fileData);
    }
}
Jack
  • 400
  • 4
  • 3
  • 5
    in the main code I was using `FileReader` this way: `var reader = new FileReader(); reader.onload = function (e) { var data = e.target.result; ..CODE HERE.. }; reader.readAsBinaryString(myFile)`. I needed to change `reader.onload` this way: `reader.onload = function (e) { if (!e) {var data = reader.content;} else {var data = e.target.result; } ..CODE HERE.. };` – Naigel Jan 28 '16 at 14:22
  • 2
    @Naigel comment was very helpful with the change he wrote. combining Jacks code and Naigels worked for me – eyalewin Feb 02 '16 at 15:22
  • 1
    `$(pt).trigger('onload');` is it jQuery's trigger method? How to do dispatch this event without jQuery? – Denis Aug 18 '16 at 14:09
9

FileReader.readAsBinaryString is a non-standard function and has been deprecated.

FileReader.readAsArrayBuffer should be used instead.

MDN

Jayendra Sharan
  • 1,043
  • 6
  • 10
7

For IE 11 you can use this XHR trick:

function blobToBinaryStringIE11(blob) {
    var blobURL = URL.createObjectURL(blob);
    var xhr = new XMLHttpRequest;
    xhr.open("get", blobURL);
    xhr.overrideMimeType("text/plain; charset=x-user-defined");
    xhr.onload = function () {
        var binary = xhr.response;
        // do stuff
    };
    xhr.send();
}

It's 20x faster than the Uint8Array + fromCharCode route and as fast as readAsBinaryString.

ozdefir
  • 191
  • 1
  • 4
1

Replace

reader.readAsBinaryString(blob);

with:

reader.readAsText(blob);

it's works well in cross browser.

user3292624
  • 180
  • 2
  • 10
  • 1
    There are problems with this. Since the browser thinks its text and not binary it can cause errors for example in firefox I got invalid characters error. – Ferus Aug 22 '18 at 14:09
0

I had some problems with the answers here and ended up making a few slight changes.

Instead of assigning to pt.content, my solution is to send a custom object to the prototype's onload, that receiver can specifically look for, I named this property msieContent so it will be very specific.

Also I used other accepted answer for converting Uint8Array to string in more robust way, you can see full details of it here: https://stackoverflow.com/a/12713326/213050

Polyfill

if (FileReader.prototype.readAsBinaryString === undefined) {
    // https://stackoverflow.com/a/12713326/213050
    function Uint8ToString(u8a: Uint8Array) {
        const CHUNK_SZ = 0x8000;
        let c = [];
        for (let i = 0; i < u8a.length; i += CHUNK_SZ) {
            c.push(String.fromCharCode.apply(null, u8a.subarray(i, i + CHUNK_SZ)));
        }
        return c.join('');
    }
    FileReader.prototype.readAsBinaryString = function (fileData) {
        const reader = new FileReader();
        reader.onload = () => this.onload({
            msieContent: Uint8ToString(new Uint8Array(<any>reader.result))
        });
        reader.readAsArrayBuffer(fileData);
    }
}

Usage

private _handleTextFile(file: File) {
    const reader = new FileReader();

    reader.onload = (e) => {
        // support for msie, see polyfills.ts
        const readResult: string = (<any>e).msieContent || <string>e.target.result;

    };

    reader.readAsBinaryString(file);
}
Community
  • 1
  • 1
FirstVertex
  • 3,657
  • 34
  • 33