900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > [开源应用]利用HTTPHandler+resumableJs+HTML5实现拖拽上传[大]文件

[开源应用]利用HTTPHandler+resumableJs+HTML5实现拖拽上传[大]文件

时间:2022-02-08 21:51:02

相关推荐

[开源应用]利用HTTPHandler+resumableJs+HTML5实现拖拽上传[大]文件

前言:

大文件传输一直是技术上的一大难点。文件过大时,一些性提交所有的内容进内存是不现实的。大文件带来问题还有是否支持断点传输和多文件同时传输。

本文以resumableJs为例,介绍了如何在中实现大文件传输。同时本文利用了Html5的新特性:支持拖拽。

本文的主要技术点在于:如何接收resumableJs的传送内容(官网不太清楚)和如何合并文件,难度并不高。如果要改为MVC中的Controller处理文件传输,方法也大同小异。

注:原博客中,此文章在原站点个人代码备份所用,注释不多,如有不懂,请在评论中给出。

效果

ASPX File:

<html xmlns="/1999/xhtml"><head runat="server"><title>Resumable.js Test</title></head><body><form id="form1" runat="server"><div id="container" style="width:300px;height:200px;background-color:lightgray"> </div></form><span id="info">welcome</span><script src="scripts/resumable.js" type="text/javascript"></script><script type="text/javascript">var showInfo = function (msg) {document.getElementById("info").innerHTML = msg;}showInfo("Test begin");var r = new Resumable({target: 'FileHandler.ashx',});r.assignBrowse(document.getElementById('container'));r.assignDrop(document.getElementById('container'));if (!r.support) showInfo("not support");r.on('fileAdded', function (file, event) {r.upload();});r.on('filesAdded', function (array) {for (var i = 0; i < array.length; i++) {var html = document.getElementById("info").innerHTML;html += "<br>"+array[i].name;}});r.on('uploadStart', function () {showInfo('start');});r.on('complete', function () {r.files.pop(); //if want to upload one file multiple times, you should remove it from r.files after completing.//pop后,才可再次重新拖拽上传此文件。此机制可避免一次上传多个文件时重复添加,但拖拽上传时不用检测。});r.on('progress', function (e) {showInfo(r.progress());});</script></body></html>

FileHandler

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Web;namespace UploadTest{/// <summary>/// Summary description for FileHandler/// </summary>public class FileHandler : IHttpHandler{string _tempFolder;object _lock = new object();public void ProcessRequest(HttpContext context){_tempFolder = context.Server.MapPath("~/temp");var method = context.Request.HttpMethod;if (method.Equals("GET")){HandleGet(context);}if (method.Equals("POST")){HandlePost(context);}}private void HandlePost(HttpContext context){var queryString = context.Request.Form;if (queryString.Count == 0) return;try{// Read parametersvar uploadToken = queryString.Get("upload_Token");int resumableChunkNumber = int.Parse(queryString.Get("resumableChunkNumber"));var resumableTotalChunks = int.Parse(queryString.Get("resumableTotalChunks"));var resumableTotalSize = long.Parse(queryString.Get("resumableTotalSize"));var resumableFilename = queryString.Get("resumableFilename");// Save Fileif (context.Request.Files.Count == 0){context.Response.StatusCode = (int).HttpStatusCode.InternalServerError; }else{var filePath = string.Format("{0}/{1}/{1}.part{2}", _tempFolder, resumableFilename, resumableChunkNumber.ToString("0000"));var directory = Path.GetDirectoryName(filePath);if (File.Exists(directory)){File.Delete(directory);}if (!Directory.Exists(directory)){Directory.CreateDirectory(directory);}if (!System.IO.File.Exists(filePath)){context.Request.Files[0].SaveAs(filePath);}if (IsCompleted(directory,resumableTotalChunks,resumableTotalSize)){MergeFiles(directory);}}}catch (Exception exception){throw exception;}}private void HandleGet(HttpContext context){var queryString = context.Request.QueryString;if (queryString.Count == 0) return;try{// Read parametersvar uploadToken = queryString.Get("upload_Token");int resumableChunkNumber = int.Parse(queryString.Get("resumableChunkNumber"));var resumableFilename = queryString.Get("resumableFilename");var resumableChunkSize = long.Parse(queryString.Get("resumableChunkSize")); var filePath = string.Format("{0}/{1}/{1}.part{2}", _tempFolder,resumableFilename, resumableChunkNumber.ToString("0000")); // Check for existance and chunksize if (System.IO.File.Exists(filePath) && new FileInfo(filePath).Length == resumableChunkSize){context.Response.Status = "200 OK";context.Response.StatusCode = 200; }else{context.Response.Status = "404 Not Found";context.Response.StatusCode = 404;}}catch (Exception exception){throw exception;}}private bool IsCompleted(string directory,int numChunks, long totalSize ){var physicalFolder = bine(_tempFolder, directory);var files = Directory.GetFiles(physicalFolder);//numbersif (files.Length != numChunks)return false;//files all exisitvar fileName = Path.GetFileName(directory);for (int i = 1; i <= numChunks; i++){var filePath = string.Format("{0}/{1}.part{2}", directory, fileName, i.ToString("0000"));if (!File.Exists(filePath)){return false;}}//size long tmpSize = 0;foreach (var file in files){tmpSize += new FileInfo(file).Length;} return totalSize==tmpSize;}private void MergeFiles(string directoryPath){lock (_lock){if (Directory.Exists(directoryPath)){var fileName = Path.GetFileName(directoryPath);var folder = Path.GetDirectoryName(directoryPath);var tempPath = bine(directoryPath + ".tmp");var files = Directory.GetFiles(directoryPath);files = files.OrderBy(f => f).ToArray();FileStream wholeStream = new FileStream(tempPath, FileMode.Append, FileAccess.Write);for(int i=0;i<files.Length;i++){ FileStream parcialStream = new FileStream(files[i], FileMode.Open);BinaryReader parcialReader = new BinaryReader(parcialStream);byte[] buffer = new byte[parcialStream.Length];buffer = parcialReader.ReadBytes((int)parcialStream.Length);BinaryWriter parcialWriter = new BinaryWriter(wholeStream);parcialWriter.Write(buffer);parcialStream.Close();}wholeStream.Close();Directory.Delete(directoryPath,true);File.Move(tempPath, directoryPath); }} }public bool IsReusable{get{return false;}} }}

附录:

1 技术难点

a. 文件过大。修改webconfig无用。

b. 断点续传。

c. 多文件上传。

2 resumable.js

API: /

工作流程:

拖文件至DIV -> 开始上传,uploadStart -> 反复触发progress事件 -> compete

主要参数:

Get:

resumableChunkNumber=1&

resumableChunkSize=1048576&

resumableCurrentChunkSize=1048576&

resumableTotalSize=27778318&

resumableType=&

resumableIdentifier=27778318-Samples7z&

resumableFilename=Samples.7z&

resumableRelativePath=Samples.7z&

resumableTotalChunks=26

Post:

—————————–111061030216033

Content-Disposition: form-data; name=”resumableChunkNumber”

140

—————————–111061030216033

Content-Disposition: form-data; name=”resumableChunkSize”

1048576

—————————–111061030216033

Content-Disposition: form-data; name=”resumableCurrentChunkSize”

1048576

—————————–111061030216033

Content-Disposition: form-data; name=”resumableTotalSize”

171309601

—————————–111061030216033

Content-Disposition: form-data; name=”resumableType”

—————————–111061030216033

Content-Disposition: form-data; name=”resumableIdentifier”

171309601-sample7z

—————————–111061030216033

Content-Disposition: form-data; name=”resumableFilename”

sample.7z

—————————–111061030216033

Content-Disposition: form-data; name=”resumableRelativePath”

sample.7z

—————————–111061030216033

Content-Disposition: form-data; name=”resumableTotalChunks”

163

—————————–111061030216033

Content-Disposition: form-data; name=”file”; filename=”blob”

Content-Type: application/octet-stream

XXXCONTENT

—————————–309022088923579–

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。