javascriptcordovacordova-plugin-file

out of memory error when calling readAsArrayBuffer method on FileReader of the cordova-plugin-file (iOS)


On iOS I'm trying to upload videos to my own website and to do so I use the FileReader.readAsArrayBuffer method with a chunkSize of 1048576.

I upload chunks when the onprogress event fires and all of this actually works perfect except for bigger files. When trying to upload a file of 1.33GB i'm getting a out of memory exception when calling the readAsArrayBuffer method.

I guess this is because it's trying to reserve memory for the complete file, however this is not necessary. Is there a way to read a binary chunk from a file without it reserving memory for the complete file? or are there other solutions?

Thanks!


Solution

  • I fixed it myself today by changing the plugin code, this is the original code:

    FileReader.prototype.readAsArrayBuffer = function (file) {
       if (initRead(this, file)) {
           return this._realReader.readAsArrayBuffer(file);
       }
    
       var totalSize = file.end - file.start;
       readSuccessCallback.bind(this)('readAsArrayBuffer', null, file.start, totalSize, function (r) {
           var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result));
           resultArray.set(new Uint8Array(r), this._progress);
           this._result = resultArray.buffer;
       }.bind(this));
    };
    

    and since at start progress is always 0, it always reserves the entire filesize. I added a propery READ_CHUNKED (because I still have other existing code that also uses this method and expects it to work as it did, i have to check to see that everything else also keeps working) and changed the above to this:

    FileReader.prototype.readAsArrayBuffer = function(file) {
        if (initRead(this, file)) {
            return this._realReader.readAsArrayBuffer(file);
        }
    
        var totalSize = file.end - file.start;
    
        readSuccessCallback.bind(this)('readAsArrayBuffer', null, file.start, totalSize, function(r) {
            var resultArray;
    
            if (!this.READ_CHUNKED) {
                resultArray = new Uint8Array(totalSize);
                resultArray.set(new Uint8Array(r), this._progress);
            } else {
                var newSize = FileReader.READ_CHUNK_SIZE;
                if ((totalSize - this._progress) < FileReader.READ_CHUNK_SIZE) {
                    newSize = (totalSize - this._progress);
                }
                resultArray = new Uint8Array(newSize);
                resultArray.set(new Uint8Array(r), 0);
            }
            this._result = resultArray.buffer;
        }.bind(this));
    };
    

    When the READ_CHUNKED property is true, it only returns the chunks and doesn't reserve memory for the entire file and when it is false it works like it used to.

    I've never used github (except for pulling code) so i'm not uploading this for now, I might look into it in the near future.