Uploading large files in a Web page has always been a headache, and the main problems are usually two categories: one is long upload time in the middle of an error will lead to naught; second, the server configuration is complex, to consider receiving super-large forms and timeouts, if the hosting host may not change the configuration, Only attachments less than 4MB are accepted by default.
The ideal solution is to be able to partition large files, one piece to the server, and then by the server to merge. The advantage of this is that once the upload failure is only a loss of a shard, not the entire file retransmission, and the size of each shard can be controlled within 4MB, the server does not have to do any settings to adapt.
The common solution is Ria, in the case of flex, usually using the Filereference.load method to load a piece to get ByteArray, and then the Shard constructs the form (the high version of Flash does not allow direct access to the file). However, this load method can only load smaller files, about 300MB, so the applicability is not very strong.
Fortunately now has the HTML5, we can directly construct the Shard, this is a very gratifying progress, but the present application surface is not wide (ie ah ie, really hate you hate tooth itch).
To get to the point, let's look at a demo, based on ASP. NET MVC3, just examples, many problems have been simplified processing.
Mainly the client, the new features are reflected here:
<%@ Page language="C #"autoeventwireup="true"Codebehind="UploadTest2.aspx.cs"inherits="Html5uploadtest.uploadtest2"%>"ZH-CN">"Utf-8"> <TITLE>HTML5 Large file multipart upload example </title> <script src="Scripts/jquery-1.8.2.js"></script> <script>varpage ={init:function () {$ ("#upload"). Click ($.proxy ( This. Upload, This)); }, Upload:function () {varFile = $ ("#file")[0].files[0],//File Objectname= File.name,//file namesize= File.size,//Total sizesucceed=0; varShardsize =2*1024x768*1024x768,//with 2MB as a shardShardcount= Math.ceil (size/shardsize);//total number of pieces for(vari =0; i < Shardcount; ++i) {//calculate the start and end positions of each slice varstart = i *shardsize, End= math.min (size, start +shardsize); //constructs a form, Formdata is the HTML5 new varform =NewFormData (); Form.append ("Data", File.slice (start, end));//slice method used to cut out part of a fileForm.append ("name", name); Form.append (" Total", Shardcount);//total number of piecesForm.append ("Index", i +1);//The current is the first few pieces//Ajax Submissions$.ajax ({URL:"upload.ashx", type:"POST", Data:form,Async:true,//AsynchronousProcessData:false,//It's important to tell jquery not to handle the form.ContentType:false,//It is important to specify false to form the correct content-typesuccess:function () {++succeed; $("#output"). Text (Succeed +" / "+shardcount); } }); } } }; $ (function () {page.init (); }); </script>"file"Id="file"/> <button id="Upload"> Uploads </button> <span id="Output"style="font-size:12px"> Wait </span></body>View CodeBackground General Handler Code
usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingsystem.web;namespacehtml5uploadtest{/// <summary> ///Summary description for Upload/// </summary> Public classUpload:ihttphandler { Public voidProcessRequest (HttpContext context) {context. Response.ContentType="Text/plain"; //take the parameters from request and note that the uploaded files are in Requst.files stringName = Context. request["name"]; intTotal = Convert.ToInt32 (context. request[" Total"]); intIndex = Convert.ToInt32 (context. request["Index"]); varData = context. request.files["Data"]; //Save a shard to disk stringDir = context. Request.mappath ("~/temp"); stringFile = Path.Combine (dir, name +"_"+index); Data. SaveAs (file); //if it is already the last Shard, the combination//of course, you can also use other methods such as receiving each shard directly to the corresponding location of the final file, but to control the concurrency to prevent file lock conflicts if(Index = =Total ) {File=Path.Combine (dir, name); varFS =NewFileStream (file, FileMode.Create); for(inti =1; I <= total; ++i) {stringPart = Path.Combine (dir, name +"_"+i); varbytes =System.IO.File.ReadAllBytes (part); Fs. Write (Bytes,0, Bytes. Length); Bytes=NULL; System.IO.File.Delete (part); } fs. Close (); } //return is successful, simplified processing is done here//return Json (new {Error = 0}); } Public BOOLisreusable {Get { return false; } } }}
View CodeThe above demo a lot of problems are simplified processing, such as did not do anything unusual processing, the client also did not determine whether the server error retry class, you can improve their own.
Based on the above, we can do a lot of functional expansion, for example, we can control whether all the shards are sequential upload or concurrent upload, for different applications. For example, we can in the overall file upload and before the upload of the Shard before the calculation of the corresponding hash, send a request to ask the server file is already there, if there is not repeated upload, so that the implementation of the "fast upload" and "breakpoint continued."
Upload oversized files with HTML5 shards