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客户端分段上传大文件相关推荐

  1. ASP.NET Web API实现简单的文件下载与上传

    ASP.NET Web API实现简单的文件下载与上传.首先创建一个ASP.NET Web API项目,然后在项目下创建FileRoot目录并在该目录下创建ReportTemplate.xlsx文件, ...

  2. NeatUpload 网络上传大文件的web.config配置问题

    本人在做网站过程中用到 NeatUpload 这个开源的大文件上传控件 开发环境:visual studio 2010 测试服务器为:win7带的 IIS7.5 在visual studio上运行的时 ...

  3. Android基础—基于Socket实现上传大文件

    上节中我们给大家接触了Socket的一些基本概念以及使用方法,然后写了一个小猪简易聊天室的 Demo,相信大家对Socket有了初步的掌握,本节我们来学习下使用Socket来实现大文件的断点续传! 这 ...

  4. php webuploader大文件,web uploader 上传大文件总结

    由于业务需要,需要上传大文件,已有的版本无法处理IE版本,经过调研,百度的 webuploader 支持 IE 浏览器,而且支持计算MD5值,进而可以实现秒传的功能. 大文件上传主要分为三部分,预上传 ...

  5. antd upload手动上传_SpringBoot 如何上传大文件?

    最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  6. SpringBoot如何上传大文件

    最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  7. ssm上传文件进度条_SSM框架+Plupload实现分块上传大文件示例

    关于Plupload的介绍,相信它的官网http://www.plupload.com/已经给得很详细了.Plupload的上传原理简单点说,就是将用户选中的文件(可多个)分隔成一个个小块,依次向服务 ...

  8. JavaScript上传大文件并支持中途取消上传

    最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  9. html5 上传超大文件,HTML5教程 如何拖拽上传大文件

    本篇教程探讨了HTML5教程 如何拖拽上传大文件,希望阅读本篇文章以后大家有所收获,帮助大家HTML5+CSS3从入门到精通 . < 前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性 ...

最新文章

  1. nodejs - 创建服务器(1)
  2. 用流读取文件中的内容
  3. C语言 之建立静态链接库
  4. Hibernate框架的配置
  5. ML之SL:监督学习(Supervised Learning)的简介、应用、经典案例之详细攻略
  6. gps matlab teqc,TEQC multipath metrics in MATLAB
  7. JavaScript中的面向对象(1):对象创建模式
  8. 电脑技巧:电脑安装操作系统、重装系统常见的问题解决方法!
  9. Eclipse里git提交冲突rejected – non-fast-forward
  10. 查一个字段中字符集超过30的列_详细解读MySQL的30条军规
  11. java随机产生坐标点_刚学JAVA不久,问一下怎么把这个程序实现随机啊,不是按照坐标...
  12. hashmap头插法和尾插法区别_Java程序员必知:HashMap进行put操作会不会引起死循
  13. FPGA学习笔记---时序逻辑与组合逻辑分析比较
  14. mysql 查询表结构
  15. 【内外网映射】通过外网ip来访问虚拟机服务器【转载】
  16. js几种加密/解密方法
  17. Unity写的3D人工智能棋类博弈小游戏-四子棋
  18. UE4 蓝图教程(三) 材质
  19. SQL Server_SQL Server Windows NT - 64 bit
  20. 计算机基础- -认识内存

热门文章

  1. 随手拈来尽是折劲额事体
  2. Linux16-防火墙与firewalld
  3. scrum项目管理_Scrum,用于初创企业(或针对该项目的任何项目)
  4. javascript晚绑定_JavaScript的应用,调用和绑定通过托管野餐来解释
  5. jpg在线合并jpg_JPG如何运作
  6. ESXi6.5环境搭建(一:VMware Workstations 12 Pro 环境的安装及配置)
  7. java50车架适合身高,【经验分享】身高与车架的选择
  8. 把.sql文件上传到服务器上
  9. Android中的多线程(字节跳动)
  10. 女士做软件测试的利弊有哪些?