"Go" file a variety of upload, inseparable from the form
"Go" file a variety of upload, inseparable from the form
As programmers, we often use the file upload and download function. When you need to use, a variety of search information. There are wood there. There is wood there .... In order to facilitate the next use, here to make a summary and memo.
File Upload with form implementation
The most primitive, simplest, and most outrageous file uploads.
Front-End Code:
//方式1<form action="/Home/SaveFile1" method="post" enctype="multipart/form-data"> <input type="file" class="file1" name="file1" /> <button type="submit" class="but1">上传</button></form>
Note
- 1. Post Submission required
- 2, enctype= "Multipart/form-data" (Transfer file)
- 3. Form elements that need to be submitted need to set the Name property
Background code:
public ActionResult SaveFile1(){ if (Request.Files.Count > 0) { Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Request.Files[0].FileName); return Content("保存成功"); } return Content("没有读到文件");}
Form asynchronous upload (Jquery.form plugin)
Although the above method is simple and rude, but not friendly enough. The page will inevitably refresh. It is difficult to implement stay on the current page, and give the file upload a successful prompt.
As time goes by, technology is changing. The advent of Ajax makes asynchronous file submissions much easier.
Below we use the Jquery.form plugin to implement asynchronous upload of files.
First we need to import jquery.js
andjquery.form.js
Front-End Code:
<form id="form2" action="/Home/SaveFile2" method="post" enctype="multipart/form-data"> <input type="file" class="file1" name="file1" /> <button type="submit" class="but1">上传1</button> <button type="button" class="but2">上传2</button></form>
//方式2(通过ajaxForm绑定ajax操作)$(function () { $(‘#form2‘).ajaxForm({ success: function (responseText) { alert(responseText); } });});//方式3(通过ajaxSubmit直接执行ajax操作)$(function () { $(".but2").click(function () { $(‘#form2‘).ajaxSubmit({ success: function (responseText) { alert(responseText); } }); });});
Background code:
public string SaveFile2(){ if (Request.Files.Count > 0) { Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName)); return "保存成功"; } return "没有读到文件";}
Principle:
We use plugins very often, regardless of the other 3,721.
If you're curious, think about how this plugin is implemented. Casually look at the source code more than 1500 lines. My mother, is not an asynchronous upload, how so complicated.
It's hard to see what the hell is going on, just debug it under a breakpoint.
The original plug-in internal IFRAME and formdata different ways to upload, to adapt to more version of the browser.
Analog form data upload (FORMDATA)
IFrame this thing is disgusting. We see above can use Formdata to upload files, this is the HTML 5 only. Let's try it out for ourselves.
Front-End Code:
<input id="fileinfo" type="file" class="notFormFile" /><button type="button" class="btnNotForm">上传4</button>
//方式4$(".btnNotForm").click(function () { var formData = new FormData();//初始化一个FormData对象 formData.append("files", $(".notFormFile")[0].files[0]);//将文件塞入FormData $.ajax({ url: "/Home/SaveFile2", type: "POST", data: formData, processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 success: function (responseText) { alert(responseText); } });});
After the code: (Unchanged, or the previous example code)
public string SaveFile2(){ if (Request.Files.Count > 0) { Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName)); return "保存成功"; } return "没有读到文件";}
We see that the Formdata object is also just simulating data in an original form format. Is it possible to upload files without using forms or form formats? The answer is yes. (as soon as the following is announced)
Front-End Code:
<input type="file" id="file5" multiple><button type="button" class="btnFile5">上传5</button>
//方式5$(".btnFile5").click(function () { $.ajax({ url: "/Home/SaveFile4", type: "POST", data: $("#file5")[0].files[0], processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 success: function (responseText) { alert(responseText); } });; });
Background code:
public string SaveFile4(){ //这里发现只能得到一个网络流,没有其他信息了。(比如,文件大小、文件格式、文件名等) Request.SaveAs(Server.MapPath("~/App_Data/SaveFile4.data") + "", false); return "保存成功";}
Careful you find that without the form format, we can not only upload the file stream data, no longer tell the background other information (such as file format).
Here, I seem to understand why the previous upload file must be wrapped in a form, originally this is only a transfer format with the background agreement.
In fact, we simply use JQ ajax to transfer text data, and finally assembled into a form format data, such as:
$.ajax({
Multipart upload
After knowing the various uploads above, are we full of the status quo? No, many times we need to transfer large files, the general server will have a certain size limit.
One day, you find a passion for a little movie that wants to share everyone. Helpless, HD files too big to pass, how to do? We can piecemeal, part of the pass, that is, the so-called multipart upload.
Front-End Code:
<input type="file" id="file6" multiple><button type="button" class="btnFile6">分片上传6</button><div class="result"></div>
Mode 6 $ (". BtnFile6"). Click (function () {var upload = function (file, skip) {var formData = new FormData (); /Initialize a Formdata object var blockSize = 1000000;//The size of each block var nextsize = math.min ((skip + 1) * blockSize, File.size );//read to the end position var fileData = File.slice (Skip * blockSize, nextsize);//Intercept part of File Block Formdata.append ("File", fileData);//plug some files into FormData formdata.append ("FileName", file.name);//Save file name $.ajax ({ URL: "/home/savefile6", type: "POST", Data:formdata, Processdata:false,//Tell Jque Ry do not process the sent data contenttype:false,//Tell jquery not to set the Content-type request header success:function (responsetext {$ (". Result"). html ("already uploaded" + (skip + 1) + "block file"); if (file.size <= nextsize) {//If the upload is complete, jump out and continue uploading alert ("Upload complete"); Return } upload (file, ++skip);//Recursive call } }); }; var file = $ ("#file6") [0].files[0]; Upload (file, 0); });
Background code:
public string SaveFile6(){ //保存文件到根目录 App_Data + 获取文件名称和格式 var filePath = Server.MapPath("~/App_Data/") + Request.Form["fileName"]; //创建一个追加(FileMode.Append)方式的文件流 using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write)) { using (BinaryWriter bw = new BinaryWriter(fs)) { //读取文件流 BinaryReader br = new BinaryReader(Request.Files[0].InputStream); //将文件留转成字节数组 byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length); //将字节数组追加到文件 bw.Write(bytes); } } return "保存成功";}
Relatively speaking, the code is a little bit more complicated. However, the code that is uploaded to other shards on the web should be much simpler (because there is no consideration for multiple file blocks uploading at the same time, the breakpoint continues to pass.) Then you need to sort the file blocks in the background, then upload to complete the sequential merge, and then delete the original temporary files. Interested students can try their own, and later in the analysis of the upload plugin Webuploader will also be implemented).
:
"description": What if we want to upload multiple files? In fact, H5 also provides a very simple way. Directly input
inside the tag multiple
, and <input type="file" id="file6" multiple>
then we receive an array in the background Request.Files
.
Use HTML5 to drag and paste uploads
Can only say H5 is really powerful ah, access to more and more big, operation more and more good.
Front-end code (drag-and-drop upload):
<textarea class="divFile7" style="min-width:800px;height:150px" placeholder="请将文件拖拽或直接粘贴到这里"></textarea>
//方式7 $(".divFile7")[0].ondrop = function (event) { event.preventDefault();//不要执行与事件关联的默认动作 var files = event.dataTransfer.files;//获取拖上来的文件 //以下代码不变 var formData = new FormData();//初始化一个FormData对象 formData.append("files", files[0]);//将文件塞入FormData $.ajax({ url: "/Home/SaveFile2", type: "POST", data: formData, processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 success: function (responseText) { alert(responseText); } }); };
Background code:
Slightly (as in previous SaveFile2)
Front-end code (paste upload limit image format):
//方式8$(".divFile7")[0].onpaste = function (event) { event.preventDefault();//不要执行与事件关联的默认动作 var clipboard = event.clipboardData.items[0];//剪贴板数据 if (clipboard.kind == ‘file‘ || clipboard.type.indexOf(‘image‘) > -1) {//判断是图片格式 var imageFile = clipboard.getAsFile();//获取文件 //以下代码不变 var formData = new FormData; formData.append(‘files‘, imageFile); formData.append(‘fileName‘, "temp.png");//这里给文件命个名(或者直接在后台保存的时候命名) $.ajax({ url: "/Home/SaveFile8", type: "POST", data: formData, processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 success: function (responseText) { alert(responseText); } }); }};
Background code:
public string SaveFile8(){ //保存文件到根目录 App_Data + 获取文件名称和格式 var filePath = Server.MapPath("~/App_Data/") + Request.Form["fileName"]; if (Request.Files.Count > 0) { Request.Files[0].SaveAs(filePath); return "保存成功"; } return "没有读到文件";}
:
Upload Plugin (webuploader)
Have enumerated the various ways to upload files, I think there is always a suitable for you. However, uploading this feature is more generic, and we can write a lot of things that are not considered. Next, simply introduce Baidu's Webuploader plugin.
Compared to our own written simple upload, its advantages: stable, good compatibility (there is flash switch, so support IE), multi-function, concurrent uploads, breakpoints continued to pass (mainly by the background with).
Official website: http://fex.baidu.com/webuploader/
Plugin Download: https://github.com/fex-team/webuploader/releases/download/0.1.5/webuploader-0.1.5.zip
The following starts the use of Webuploader
The first kind, simple and rude.
Front-End Code:
<div id="picker">选择文件</div><button id="ctlBtn" class="btn btn-default">开始上传</button>
<!--引用webuploader的js和css--><link href="~/Scripts/webuploader-0.1.5/webuploader.css" rel="stylesheet" /><script src="~/Scripts/webuploader-0.1.5/webuploader.js"></script><script type="text/javascript"> var uploader = WebUploader.create({ // (如果是新浏览器 可以不用 flash) //swf: ‘/Scripts/webuploader-0.1.5/Uploader.swf‘, // 文件接收服务端。 server: ‘/Webuploader/SaveFile‘, // 选择文件的按钮。可选。 // 内部根据当前运行是创建,可能是input元素,也可能是flash. pick: ‘#picker‘ }); $("#ctlBtn").click(function () { uploader.upload(); }); uploader.on(‘uploadSuccess‘, function (file) { alert("上传成功"); });</script>
Background code:
public string SaveFile(){ if (Request.Files.Count > 0) { Request.Files[0].SaveAs(Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName)); return "保存成功"; } return "没有读到文件";}
Second, multipart upload. Similar to the effect we wrote before.
Front-End Code:
var uploader = WebUploader.create({ //兼容老版本IE swf: ‘/Scripts/webuploader-0.1.5/Uploader.swf‘, // 文件接收服务端。 server: ‘/Webuploader/SveFile2‘, // 开起分片上传。 chunked: true, //分片大小 chunkSize: 1000000, //上传并发数 threads: 1, // 选择文件的按钮。 pick: ‘#picker‘});// 点击触发上传$("#ctlBtn").click(function () { uploader.upload();});uploader.on(‘uploadSuccess‘, function (file) { alert("上传成功");});
Background code:
public string SveFile2(){ //保存文件到根目录 App_Data + 获取文件名称和格式 var filePath = Server.MapPath("~/App_Data/") + Path.GetFileName(Request.Files[0].FileName); //创建一个追加(FileMode.Append)方式的文件流 using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write)) { using (BinaryWriter bw = new BinaryWriter(fs)) { //读取文件流 BinaryReader br = new BinaryReader(Request.Files[0].InputStream); //将文件留转成字节数组 byte[] bytes = br.ReadBytes((int)Request.Files[0].InputStream.Length); //将字节数组追加到文件 bw.Write(bytes); } } return "保存成功";}
We see a parameter threads: 1
upload concurrency number, what if we change to more than 1? The front end initiates multiple file uploads simultaneously. The background will be error, multiple processes simultaneously manipulate a file.
What if we want multi-threaded uploads? Change the code (mainly background logic).
Front-End Code:
//并发上传(多线程上传)var uploader = WebUploader.create({ //兼容老版本IE swf: ‘/Scripts/webuploader-0.1.5/Uploader.swf‘, // 文件接收服务端。 server: ‘/Webuploader/SveFile3‘, // 开起分片上传。 chunked: true, //分片大小 chunkSize: 1000000, //上传并发数 threads: 10, // 选择文件的按钮。 pick: ‘#picker‘});// 点击触发上传$("#ctlBtn").click(function () { uploader.upload();});uploader.on(‘uploadSuccess‘, function (file) { //上传完成后,给后台发送一个合并文件的命令 $.ajax({ url: "/Webuploader/FileMerge", data: { "fileName": file.name }, type: "post", success: function () { alert("上传成功"); } });});
Background code:
public String SveFile3 () {var chunk = request.form["Chunk"];//is currently the number of pieces of var path = Server.MapPath ("~/app_d ata/") + path.getfilenamewithoutextension (request.files if (! Directory.Exists (path)//Determine if this path exists, or create {directory.createdirectory (path) if it does not exist; }//save file to root directory App_Data + get file name and format var filePath = path + "/" + chunk; Create an append (filemode.append) mode for the file stream using (FileStream fs = new FileStream (FilePath, Filemode.append, FileAccess.Write)) {using (BinaryWriter bw = new BinaryWriter (FS)) {//Read file stream binaryreader br = new Binar Yreader (Request.files[0]. InputStream); Leave the file in a byte array byte[] bytes = br. Readbytes ((int) request.files[0]. Inputstream.length); Appends a byte array to the file BW. Write (bytes); }} return "saved successfully";}
///<summary>///Merge files///</summary>///<param name= "path" ></param>///<returns ></returns>public bool Filemerge () {var fileName = request.form["filename"]; var path = Server.MapPath ("~/app_data/") + path.getfilenamewithoutextension (fileName); Here the sort must be correct, turn into a number after sorting (string will be sorted by 1 10 11, default 10:2 small) foreach (Var filePath in Directory.GetFiles (path). (t = int). Parse (Path.getfilenamewithoutextension (t)))) {using (FileStream fs = new FileStream (Server.MapPath ("~/app_data/ ") + FileName, Filemode.append, FileAccess.Write) {byte[] bytes = System.IO.File.ReadAllBytes (filePath );//Read file to byte array fs. Write (bytes, 0, bytes. LENGTH);//write File} System.IO.File.Delete (FilePath); } directory.delete (path); return true;}
You think it's over when you get here? Wrong, there are a lot of things not to be considered. What happens if multiple users upload a file name? How do I implement a breakpoint continuation? Not yet implemented select multiple files? However, here is not going to continue to paste the code (again, the amount of code more and more), you also come to practice it.
Provide a way to insert a data into the database before uploading. The data contains the path of the file to be saved, the file name (named with the GUID, prevent file conflicts with the same name), the files MD5 (to identify the next continuation and second pass), the temporary file Block storage path, the file is a complete upload of the success of information.
Then if we break the net and then pass, first get the file MD5 value, look at the database has not uploaded the complete file, if there is the realization of the second pass. If not, see if there is part of the upload. If there is a pass, re-upload a new file if it is not.
Summarize
I have always wondered why uploading files must be wrapped up in a form, and now it's probably clear.
At first, when JavaScript was not popular, we were able to submit form data directly using the Submit button. The form can contain text and files. Then, with the popularity of JS and Ajax, you can use Ajax to directly submit part of the form data asynchronously. I'm starting to get tangled up here, why Ajax can submit its own assembled data. Then why not submit the file directly? I am wrong here, Ajax submitted is not random data, and finally assembled into a form format (because the background technology for form format data support more popular). But the existing technology is not able to assemble a file format form data via JS. Until Formdata appears in H5, it is possible for the front-end JS to assemble a form format data containing files. So the form is just for the data format that meets the "Conventions" in the background.
Related recommendations
- Http://www.cnblogs.com/fish-li/archive/2011/07/17/2108884.html
- Http://javascript.ruanyifeng.com/htmlapi/file.html
Demo
- https://github.com/zhaopeiym/BlogDemoCode/tree/master/Upload and download
"Go" file a variety of upload, inseparable from the form