Split file with JavaScript or jQuery

16,353

Since you're using FormData, which is a fairly new technology, I'll show you something with new technologies as well.

First, read the file with a FileReader object:

var fr = new FileReader(), buf, file = $('#fileUpload')[0].files[0];
fr.onload = function(e) {
    buf = new Uint8Array(e.target.result);
};
fr.readAsArrayBuffer(file);

Then you can create a Blob for each splitted part (1e6 bytes long each):

for (var i = 0, blobs = []; i < buf.length; i += 1e6)
    blobs.push(new Blob([buf.subarray(i, i + 1e6)]));

Finally, you can add all your Blobs to your FormData object:

var formData = new FormData();
for (var i = 0; i < blobs.length; i++)
    formData.append("slice" + i, blobs[i], file.name + ".part" + i);

You should be ok. I haven't tested it, though.

I don't know anything about the performance either. You can use fr.readAsBinaryString too, thus making e.target.result a string. This way, you can create the Blobs using a simple substring/slice/substr/whatever, but I fear there could be some problems with Unicode characters and whatnot. Plus, maybe it's slower.

Putting everything in a more coherent snippet:

$('#fileUpload').change(function() {
    // If no file is selected, there's nothing to do
    if (!this.files.length) return;

    var fr = new FileReader(), file = this.files[0];
    fr.onload = function(e) {
        splitAndSendFile(new Uint8Array(e.target.result), file);
    };
    fr.readAsArrayBuffer(file);
};

function splitAndSendFile(dataArray, file) {
    var i = 0, formData, blob;
    for (; i < dataArray.length; i += 1e6) {
        blob = new Blob([dataArray.subarray(i, i + 1e6)]);
        formData = new FormData();
        formData.append("fileUpload", blob, file.name + ".part" + (i / 1e6));
        $.ajax({
            url: 'script.php',
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(msg){
                alert("Win: " + msg);
            },
            error: function(bla, msg){
                alert("Fail: " + msg);
            }
        });
    }
}

Note: FormData.append takes a third optional parameter, which should be the name of the file in case of File or Blob values. If not specified, Blobs may get unpredictable random file names.

Probably that parameter isn't standard, and it's not mentioned in the MDN artice, but I used it in the snippet above nonetheless. Anyway, if you know what you're doing, you can have several options to specify the file name. For example, with formData.append("filename", file.name) or sending a custom header in the request.

Share:
16,353
Sylnois
Author by

Sylnois

Updated on June 03, 2022

Comments

  • Sylnois
    Sylnois almost 2 years

    I need to upload a part of a file (only the first MB). I've created a PHP script which uploads the whole file. The data (formData Object) is passed by a ajax call.

    My idea would be now to split the file with javascript (jquery). Is there any solution for my request?

    Current code:

    function start(a){
        //var fSize = $('#fileUpload')[0].files[0].size / 1024;
        var formData = new FormData();    
        formData.append( 'fileUpload', $('#fileUpload')[0].files[0] );
        //AJAX
        $.ajax({
            url: 'script.php',
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(msg){
                alert("Win: " + msg);
            },
            error: function(bla, msg){
                alert("Fail: " + msg);
            }
        });
    }
    
    • RoToRa
      RoToRa over 11 years
      You don't have any access to the content file in JavaScript. There is no way to split it. And BTW there is no way to post a file with AJAX either.
    • Admin
      Admin over 11 years
      @RoToRa Why don't you post it as an answer?
    • raina77ow
      raina77ow over 11 years
      @RoToRa Well, actually there's a way - with new FileReader API. But somehow I think it's not relevant here. )
    • raina77ow
      raina77ow over 11 years
      @user1515190 I suppose this article might be helpful for you. But take note that tools used in it are not universally supported... yet.
    • Sylnois
      Sylnois over 11 years
      @RoToRa ehm, this script above works.
  • Sylnois
    Sylnois over 11 years
    Thanks for your reply. I don't want to send the whole array, just part for part(so i can control the progressbar), but somehow it does not work(link to my script at the end). My PHP-Script is a simple command(move_uploaded_file($_FILES["fileUpload"]["tmp_name"]‌​, $uploadPath . $_FILES["fileUpload"]["name"]);). I want to fit the parts together serverside. 193.109.52.60/dario/f
  • MaxArt
    MaxArt over 11 years
    @user1515190 It doesn't work because of a syntax error in the blob.push(... line. Missed a closing parenthesis, my bad. You can try it again.
  • Sylnois
    Sylnois over 11 years
    still not working :/ PS: Really thanks for your help! I try this for weeks(not full-time of course :D)
  • MaxArt
    MaxArt over 11 years
    @user1515190 Ah, I get it. Now the problem is in your code. I didn't put everything in a complete form, but it can't be done in a synchronous way. I'll give you a hint about it, in the answer.
  • Sylnois
    Sylnois over 11 years
    Something still not right. I've tried to debug my code with alerts. Alert 6 does not appaer(after this code section: blob = new Blob([dataArray.subarray(i, i + 1e6)]);
  • MaxArt
    MaxArt over 11 years
    @user1515190 It works perfectly for me, "bla6" is alerted and then I get a "Win" alert with the size of the sent chunk. I'm using Chrome 22 dev. Why don't you debug with the developer tools of your browser instead of the old fashioned alerts? Which one are you using?
  • Sylnois
    Sylnois over 11 years
    i can see your files(AEVLX.gif.part0 - part2). I'm using Chrome 18.0.1025.162. When i try to upload a ZIP-file, nothing happens. Only the first four alerts appear.
  • Sylnois
    Sylnois over 11 years
    i updated my google chrome to 21 and now it works.. but whats with the people with older browser?
  • Sylnois
    Sylnois over 11 years
    large files still not working :( browser crashes after trying to upload a 25 MB big RAR-file
  • MaxArt
    MaxArt over 11 years
    @user1515190 That's probably because of a memory overflow of some sort. I don't think file splitting is a task for browsers, anyway: that's the major problem. People with older browsers... well, should upgrade before using your app. Chrome, Firefox and Opera usually upgrades automatically. IE is out of question in this case, so you shouldn't worry about it. It's not a tragedy to ask your users to upgrade to browsers with a good HTML5 support.
  • Sylnois
    Sylnois over 11 years
    It is, cause in many companies is the ie(an older version) default and the employees can't just upgrade the software, but many THANKS four your help, really! A last question: i've done this partions that i can show up an progressbar. Do you know another way to show up an progressbar with JQuery? without flash or any other extensions :)
  • MaxArt
    MaxArt over 11 years
    @user1515190 IE, even IE9, doesn't support FormData, nor XHR2 requests, so you're out of luck with this bunch of code. If your aim was to show a progress bar, then you could just rely on the onprogress event of the upload member of the XHR object, getting a much better result than all the pain we got through. As for the progress bar, I'd suggest to use some common jQuery plugins, for example the progress bar of jQuery UI, which is like an "official" widget library for jQuery. (BTW, can you accept my answer if it helped you?)
  • Thomas
    Thomas over 8 years
    what is FormData and FileReader class?
  • MaxArt
    MaxArt over 8 years
    @Thomas They're API that are part of the XHR2 standard interface. They're available in IE10+ and evergreen browsers.
  • Karan Bhandari
    Karan Bhandari over 6 years
    Thank you, used your code as base to do the same with angular js. github.com/kurtzace/angular-multipart-smaller-chunks