0

I am experimenting some HTML5 APIs like FileReader, Blob and etc. I am trying to slice a file into chunks, read each chunk as array buffer, create a blob by adding all the chunked array buffers together, and then reconstruct the file. The issue i am having is after reconstruct the file, the file is corrupted for most file types except for text files which are fine. Any idea why? Below is the code i have so far.

JSFiddle Code Sample

<input type="file" id="files" name="files[]" multiple><button id="a">anaylze</button>



 document.getElementById('a').addEventListener('click', sliceFileToSend, false);
document.getElementById('files').addEventListener('change', handleFileSelect, false);
var files;
var blob = new Blob();
var filename='';

function handleFileSelect(evt) {
  files = evt.target.files; 
}

function sliceFileToSend() {
  console.log("enter sliceFileToSend function");

  if (typeof files !== 'undefined') {
    for (var j = 0, len = files.length; j < len; j++) {
      if (files[j].size > 25 * 1024 * 1024) {
        continue;
      }
      filename=files[j].name;
      alert(JSON.stringify({
        filename: files[j].name
      }));

      parseFile(files[j]);
    }
  }
}

function parseFile(file) {
  var fileSize = file.size;
  var chunkSize = 16 * 1024; // bytes
  var offset = 0;  
  var block = null;


  var foo = function(evt) {
    if (evt.target.error === null) {
      offset += evt.target.result.byteLength;
      blob = new Blob([evt.target.result,blob]); // callback for handling read chunk
    }
    else {
      console.log("Read error: " + evt.target.error);
      return;
    }
    if (offset >= fileSize) {
      console.log("Done reading file");
      alert({
        isEnded: true
      });
      saveFile(blob,filename);
      return;
    }

    block(offset, chunkSize, file);
  };

  block = function(_offset, length, _file) {
    var r = new FileReader();
    var blob = _file.slice(_offset, length + _offset);
    r.onload = foo;
    r.readAsArrayBuffer(blob);
  };

  block(offset, chunkSize, file);
}

function saveFile(blob, fileName) {
  var link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = fileName;
  link.click();
}
3
  • It does not work for text files either, the input and the output are different (I compared using Beyond Compare). There is probably something wrong with your logic (the first about 8194 characters are missing, for example). Commented May 6, 2015 at 6:16
  • Thanks Phistuck.. I will look into my logic again. Commented May 6, 2015 at 14:58
  • But, please, do share the answer, even as self answered. Commented May 6, 2015 at 16:25

2 Answers 2

1

Without looking too closely:

blob = new Blob([evt.target.result,blob])

This appears to be prepending each chunk's data, whereas you're increasing the offset of each chunk. So the chunks would be reassembled in reverse.

Sign up to request clarification or add additional context in comments.

2 Comments

you got it...i was gonna post the answer, and there are still other issues within my script. I am working on it, and hopefully post the perfect answer later
after fixing --> blob = new Blob([blob,evt.target.result]), it works perfectly with one file selection. However for multiple files, there are issues. Main issue is the parseFile function doesnt block the forloop which i thought it should?, so all the variables are overwritten by next loop before the parseFile finished processing.
0
    document.getElementById('a').addEventListener('click', sliceFileToSend, false);
   document.getElementById('files').addEventListener('change', handleFileSelect, false);
        var files;


        function handleFileSelect(evt) {
          files = evt.target.files; 
        }

        function sliceFileToSend() {
          console.log("enter sliceFileToSend function");

          if (typeof files !== 'undefined') {
            for (var j = 0, len = files.length; j < len; j++) {
              if (files[j].size > 25 * 1024 * 1024) {
                continue;
              }
              parseFile(files[j]);
            }
          }
        }

        function parseFile(file) {
          var fileSize = file.size;
          var chunkSize = 16 * 1024; // bytes
          var offset = 0;  
          var block = null;
          var blob = new Blob();
          var filename=file.name;



          var foo = function(evt) {
            if (evt.target.error === null) {
              offset += evt.target.result.byteLength;
              blob = new Blob([blob,evt.target.result]); // callback for handling read chunk
            }
            else {
              console.log("Read error: " + evt.target.error);
              return;
            }
            if (offset >= fileSize) {
              console.log("Done reading file");
              alert("Done reading file");
              saveFile(blob,filename);
              offset=0;
              blob = null;
              return;
            }

            block(offset, chunkSize, file);
          };

          block = function(_offset, length, _file) {
            var r = new FileReader();
            var blob = _file.slice(_offset, length + _offset);
            r.onload = foo;
            r.readAsArrayBuffer(blob);
          };

          block(offset, chunkSize, file);
        }

        function saveFile(blob, fileName) {
          var link = document.createElement('a');
          link.href = window.URL.createObjectURL(blob);
          link.download = fileName;
          link.click();
        }

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.