Web API之基于H5客户端分段上传大文件
http://www.cnblogs.com/OneDirection/articles/7285739.html
查询很多资料没有遇到合适的,对于MultipartFormDataStreamProvider 也并是很适合,总会出现问题。于是放弃,使用了传统的InputStream 分段处理完之后做merge处理。
前台分段规则 命名要规范,传递分段总文件数便于判定分段上传完成做merge处理。merge需要根据分段顺序并在merge成功后删除分段文件。
var FilePartName = file.name + ".part_" + PartCount + "." + TotalParts;
前台JS代码:
<script>$(document).ready(function () {$('#btnUpload').click(function () {var files = $('#uploadfile')[0].files;for (var i = 0; i < files.length; i++) {UploadFile(files[i]);}});});function UploadFileChunk(Chunk, FileName) {var fd = new FormData();fd.append('file', Chunk, FileName);fd.append('UserName', 'ming.lu@genewiz.com');fd.append('BusinessLine', '1');fd.append('ServiceItemType', '109');fd.append('Comment', 'This is order comment for GA order');fd.append('UserId', '43F0FEDF-E9AF-4289-B71B-54807BCB8CD9');$.ajax({type: "POST",url: 'http://localhost:50821/api/customer/GA/SaveSangerCameraOrder',contentType: false,processData: false,data: fd,success: function (data) {alert(data);},error: function (data) {alert(data.status + " : " + data.statusText + " : " + data.responseText);}});}function UploadFile(TargetFile) {// create array to store the buffer chunksvar FileChunk = [];// the file object itself that we will work withvar file = TargetFile;// set up other initial varsvar MaxFileSizeMB = 5;var BufferChunkSize = MaxFileSizeMB * (1024 * 1024);var ReadBuffer_Size = 1024;var FileStreamPos = 0;// set the initial chunk lengthvar EndPos = BufferChunkSize;var Size = file.size;// add to the FileChunk array until we get to the end of the filewhile (FileStreamPos < Size) {// "slice" the file from the starting position/offset, to the required lengthFileChunk.push(file.slice(FileStreamPos, EndPos));FileStreamPos = EndPos; // jump by the amount readEndPos = FileStreamPos + BufferChunkSize; // set next chunk length}// get total number of "files" we will be sendingvar TotalParts = FileChunk.length;var PartCount = 0;// loop through, pulling the first item from the array each time and sending itwhile (chunk = FileChunk.shift()) {PartCount++;// file name conventionvar FilePartName = file.name + ".part_" + PartCount + "." + TotalParts;// send the fileUploadFileChunk(chunk, FilePartName);}} </script>
MaxFileSizeMB参数设置分段大小 ,测试例子为5M
chunk = FileChunk.shift() 在分段上传成功之后删除已上传分段
1
|
HTML代码:
|
<h2>Test Multiple Chunk Upload</h2><p><input type="file" name="uploadfile" id="uploadfile" multiple="multiple" /><br /><a href="#" id="btnUpload" class="btn btn-primary">Upload file</a></p>
后台webapi controller代码:
/// <summary>/// Upload sanger camera order /// </summary>/// <param name="model">user id and user email are required</param>/// <returns></returns>[HttpPost][Route("api/customer/GA/SaveSangerCameraOrder")][MimeMultipart]public HttpResponseMessage SaveSangerCameraOrder(){var files = HttpContext.Current.Request.Files;if (files.Count <= 0){return new HttpResponseMessage(){StatusCode = System.Net.HttpStatusCode.OK,Content = new StringContent(ConstantStringHelper.API_FAILED)};}//receice request form parametersvar userName = HttpContext.Current.Request.Form["UserName"];var businessLine = HttpContext.Current.Request.Form["BusinessLine"];var serviceItemType = HttpContext.Current.Request.Form["ServiceItemType"];var comment = HttpContext.Current.Request.Form["Comment"];var userId = HttpContext.Current.Request.Form["UserId"];if (string.IsNullOrEmpty(userName)) userName = "UnknownUser";string dateTimeTicket = string.Format("{0:yyyy-MM-dd}", System.DateTime.Now);var storagePath = ConfigurationManager.AppSettings["SangerOrderStorageLocation"].ToString();var fileSavePath = storagePath + @"/" + userName + "/" + dateTimeTicket + "/";foreach (string file in files){var FileDataContent = HttpContext.Current.Request.Files[file];if (FileDataContent != null && FileDataContent.ContentLength > 0){// take the input stream, and save it to a temp folder using// the original file.part name postedvar stream = FileDataContent.InputStream;var fileName = Path.GetFileName(FileDataContent.FileName);var UploadPath = HttpContext.Current.Request.MapPath(fileSavePath);Directory.CreateDirectory(UploadPath);string path = Path.Combine(UploadPath, fileName);if (System.IO.File.Exists(path))System.IO.File.Delete(path);using (var fileStream = System.IO.File.Create(path)){stream.CopyTo(fileStream);}// Once the file part is saved, see if we have enough to merge itUtils UT = new Utils();var isMergedSuccess = UT.MergeFile(path);if (isMergedSuccess){//generate txt document for customer commentstring timeTicket = string.Format("{0:yyyyMMddHHmmss}", System.DateTime.Now);FileStream fs = new FileStream(UploadPath + timeTicket + "OrderComment.txt", FileMode.Create);//get bytebyte[] data = System.Text.Encoding.Default.GetBytes(comment);//writefs.Write(data, 0, data.Length);//clear and clost streamfs.Flush();fs.Close();}}}return new HttpResponseMessage(){StatusCode = System.Net.HttpStatusCode.OK,Content = new StringContent(ConstantStringHelper.API_SUCCESS)};}
工具类代码:
记得关闭stream
public class Utils{public string FileName { get; set; }public string TempFolder { get; set; }public int MaxFileSizeMB { get; set; }public List<String> FileParts { get; set; }public Utils(){FileParts = new List<string>();}/// <summary>/// original name + ".part_N.X" (N = file part number, X = total files)/// Objective = enumerate files in folder, look for all matching parts of split file. If found, merge and return true./// </summary>/// <param name="FileName"></param>/// <returns></returns>public bool MergeFile(string FileName){bool rslt = false;// parse out the different tokens from the filename according to the conventionstring partToken = ".part_";string baseFileName = FileName.Substring(0, FileName.IndexOf(partToken));string trailingTokens = FileName.Substring(FileName.IndexOf(partToken) + partToken.Length);int FileIndex = 0;int FileCount = 0;int.TryParse(trailingTokens.Substring(0, trailingTokens.IndexOf(".")), out FileIndex);int.TryParse(trailingTokens.Substring(trailingTokens.IndexOf(".") + 1), out FileCount);// get a list of all file parts in the temp folderstring Searchpattern = Path.GetFileName(baseFileName) + partToken + "*";string[] FilesList = Directory.GetFiles(Path.GetDirectoryName(FileName), Searchpattern);// merge .. improvement would be to confirm individual parts are there / correctly in sequence, a security check would also be important// only proceed if we have received all the file chunksif (FilesList.Count() == FileCount){// use a singleton to stop overlapping processesif (!MergeFileManager.Instance.InUse(baseFileName)){MergeFileManager.Instance.AddFile(baseFileName);if (File.Exists(baseFileName))File.Delete(baseFileName);// add each file located to a list so we can get them into // the correct order for rebuilding the fileList<SortedFile> MergeList = new List<SortedFile>();foreach (string file in FilesList){SortedFile sFile = new SortedFile();sFile.FileName = file;baseFileName = file.Substring(0, file.IndexOf(partToken));trailingTokens = file.Substring(file.IndexOf(partToken) + partToken.Length);int.TryParse(trailingTokens.Substring(0, trailingTokens.IndexOf(".")), out FileIndex);sFile.FileOrder = FileIndex;MergeList.Add(sFile);}// sort by the file-part number to ensure we merge back in the correct ordervar MergeOrder = MergeList.OrderBy(s => s.FileOrder).ToList();using (FileStream FS = new FileStream(baseFileName, FileMode.Create)){try{// merge each file chunk back into one contiguous file streamforeach (var chunk in MergeOrder){using (FileStream fileChunk = new FileStream(chunk.FileName, FileMode.Open)){fileChunk.CopyTo(FS);fileChunk.Flush();fileChunk.Close();fileChunk.Dispose();}}foreach (var item in FilesList){if (File.Exists(item))File.Delete(item);}}catch (Exception ex){FS.Flush();FS.Close();FS.Dispose();throw new Exception(ex.Message);}}rslt = true;// unlock the file from singletonMergeFileManager.Instance.RemoveFile(baseFileName);}}return rslt;}public List<string> SplitFiles(){//bool rslt = false;string BaseFileName = Path.GetFileName(FileName);// set the size of file chunk we are going to split intoint BufferChunkSize = 5 * (1024 * 1024); //5MB// set a buffer size and an array to store the buffer data as we read itconst int READBUFFER_SIZE = 1024;byte[] FSBuffer = new byte[READBUFFER_SIZE];// open the file to read it into chunksusing (FileStream FS = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read)){// calculate the number of files that will be createdint TotalFileParts = 0;if (FS.Length < BufferChunkSize){TotalFileParts = 1;}else{float PreciseFileParts = ((float)FS.Length / (float)BufferChunkSize);TotalFileParts = (int)Math.Ceiling(PreciseFileParts);}int FilePartCount = 0;// scan through the file, and each time we get enough data to fill a chunk, write out that filewhile (FS.Position < FS.Length){string FilePartName = String.Format("{0}.part_{1}.{2}",BaseFileName, (FilePartCount + 1).ToString(), TotalFileParts.ToString());FilePartName = Path.Combine(TempFolder, FilePartName);FileParts.Add(FilePartName);using (FileStream FilePart = new FileStream(FilePartName, FileMode.Create)){int bytesRemaining = BufferChunkSize;int bytesRead = 0;while (bytesRemaining > 0 && (bytesRead = FS.Read(FSBuffer, 0,Math.Min(bytesRemaining, READBUFFER_SIZE))) > 0){FilePart.Write(FSBuffer, 0, bytesRead);bytesRemaining -= bytesRead;}}// file written, loop for next chunkFilePartCount++;}}return FileParts;//return rslt;}}public struct SortedFile{public int FileOrder { get; set; }public String FileName { get; set; }}public class MergeFileManager{private static MergeFileManager instance;private List<string> MergeFileList;private MergeFileManager(){try{MergeFileList = new List<string>();}catch { }}public static MergeFileManager Instance{get{if (instance == null)instance = new MergeFileManager();return instance;}}public void AddFile(string BaseFileName){MergeFileList.Add(BaseFileName);}public bool InUse(string BaseFileName){return MergeFileList.Contains(BaseFileName);}public bool RemoveFile(string BaseFileName){return MergeFileList.Remove(BaseFileName);}}
如该文件分六段上传,则会提示六次success,可以按照自己业务处理。
转载于:https://www.cnblogs.com/yibinboy/p/7746973.html
Web API之基于H5客户端分段上传大文件相关推荐
- ASP.NET Web API实现简单的文件下载与上传
ASP.NET Web API实现简单的文件下载与上传.首先创建一个ASP.NET Web API项目,然后在项目下创建FileRoot目录并在该目录下创建ReportTemplate.xlsx文件, ...
- NeatUpload 网络上传大文件的web.config配置问题
本人在做网站过程中用到 NeatUpload 这个开源的大文件上传控件 开发环境:visual studio 2010 测试服务器为:win7带的 IIS7.5 在visual studio上运行的时 ...
- Android基础—基于Socket实现上传大文件
上节中我们给大家接触了Socket的一些基本概念以及使用方法,然后写了一个小猪简易聊天室的 Demo,相信大家对Socket有了初步的掌握,本节我们来学习下使用Socket来实现大文件的断点续传! 这 ...
- php webuploader大文件,web uploader 上传大文件总结
由于业务需要,需要上传大文件,已有的版本无法处理IE版本,经过调研,百度的 webuploader 支持 IE 浏览器,而且支持计算MD5值,进而可以实现秒传的功能. 大文件上传主要分为三部分,预上传 ...
- antd upload手动上传_SpringBoot 如何上传大文件?
最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- SpringBoot如何上传大文件
最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- ssm上传文件进度条_SSM框架+Plupload实现分块上传大文件示例
关于Plupload的介绍,相信它的官网http://www.plupload.com/已经给得很详细了.Plupload的上传原理简单点说,就是将用户选中的文件(可多个)分隔成一个个小块,依次向服务 ...
- JavaScript上传大文件并支持中途取消上传
最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- html5 上传超大文件,HTML5教程 如何拖拽上传大文件
本篇教程探讨了HTML5教程 如何拖拽上传大文件,希望阅读本篇文章以后大家有所收获,帮助大家HTML5+CSS3从入门到精通 . < 前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性 ...
最新文章
- nodejs - 创建服务器(1)
- 用流读取文件中的内容
- C语言 之建立静态链接库
- Hibernate框架的配置
- ML之SL:监督学习(Supervised Learning)的简介、应用、经典案例之详细攻略
- gps matlab teqc,TEQC multipath metrics in MATLAB
- JavaScript中的面向对象(1):对象创建模式
- 电脑技巧:电脑安装操作系统、重装系统常见的问题解决方法!
- Eclipse里git提交冲突rejected – non-fast-forward
- 查一个字段中字符集超过30的列_详细解读MySQL的30条军规
- java随机产生坐标点_刚学JAVA不久,问一下怎么把这个程序实现随机啊,不是按照坐标...
- hashmap头插法和尾插法区别_Java程序员必知:HashMap进行put操作会不会引起死循
- FPGA学习笔记---时序逻辑与组合逻辑分析比较
- mysql 查询表结构
- 【内外网映射】通过外网ip来访问虚拟机服务器【转载】
- js几种加密/解密方法
- Unity写的3D人工智能棋类博弈小游戏-四子棋
- UE4 蓝图教程(三) 材质
- SQL Server_SQL Server Windows NT - 64 bit
- 计算机基础- -认识内存
热门文章
- 随手拈来尽是折劲额事体
- Linux16-防火墙与firewalld
- scrum项目管理_Scrum,用于初创企业(或针对该项目的任何项目)
- javascript晚绑定_JavaScript的应用,调用和绑定通过托管野餐来解释
- jpg在线合并jpg_JPG如何运作
- ESXi6.5环境搭建(一:VMware Workstations 12 Pro 环境的安装及配置)
- java50车架适合身高,【经验分享】身高与车架的选择
- 把.sql文件上传到服务器上
- Android中的多线程(字节跳动)
- 女士做软件测试的利弊有哪些?