using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Configuration; namespace WebApplication1
{
/// <summary>
/// PartialFileSet 的摘要说明
/// </summary>
public class UpLoadPartialFile : IHttpHandler
{
public static DateTime mkdirRecodeTime = DateTime.Now.AddDays(-);
public static string keyHead = DateTime.Now.Year + "" + DateTime.Now.Month + DateTime.Now.Day;
public static string path = ConfigurationManager.AppSettings["filePath"].ToString();
public static object mkdirLock = new object(); /// <summary>
/// 根据日期字符串返回路径
/// </summary>
/// <param name="keyHead">日期字符串yyyyMMdd</param>
/// <returns></returns>
private static string getCurrentPathByDate(string keyHead)
{ return path + "\\" + keyHead;
} private static string getCurrentFilePathByDate(string keyHead, string guid, int id)
{
return getCurrentPathByDate(keyHead) + "\\" + guid + id;
} private static string getNewFilePathByDate(string keyHead, string guid)
{
string fileType = HttpContext.Current.Request["fileType"];
if(fileType!=null&& fileType.Length>)
return getCurrentPathByDate(keyHead) + "\\" + guid+"."+fileType;
return getCurrentPathByDate(keyHead) + "\\" + guid;
}
/// <summary>
/// 如果目标文件夹不存在 创建文件夹
/// </summary>
/// <param name="keyHead"></param>
private static void mkdirIfNoExit()
{ if ((DateTime.Now-mkdirRecodeTime ).Days < )
return; //创建文件夹目录
if (Directory.Exists(getCurrentPathByDate(keyHead)))
return;
lock (mkdirLock)
{ if (!Directory.Exists(path))
Directory.CreateDirectory(path);
if (!Directory.Exists(getCurrentPathByDate(keyHead)))
Directory.CreateDirectory(getCurrentPathByDate(keyHead)); keyHead = DateTime.Now.Year + "" + DateTime.Now.Month + DateTime.Now.Day;
mkdirRecodeTime = DateTime.Now;
return;
} } private void uploadFile(HttpContext context)
{
try
{
//检查目录
mkdirIfNoExit(); if (context.Request.Files == null || context.Request.Files.Count == || context.Request.Files[].InputStream.Length == )
{
context.Response.Write("{\"state\":\"error\",\"code\":-6,\"msg\":\"接口调用出错 上传文件不能为空\"}");
return;
}
if (context.Request.Files.Count > )
{
context.Response.Write("{\"state\":\"error\",\"code\":-7,\"msg\":\"接口调用出错 每次只能上传单个文件\"}");
return;
}
string guid = Guid.NewGuid().ToString(); string keyHead = DateTime.Now.Year + "" + DateTime.Now.Month + DateTime.Now.Day;
string currentPath = getCurrentPathByDate(keyHead);
string filePath = getNewFilePathByDate(keyHead, guid); lock (filePath)
{
//创建文件
try
{
context.Request.Files[].SaveAs(filePath); }
catch (Exception e)
{
Util.LogHelper.Info(e.Message + e.StackTrace); context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错 guid为" + guid + "的文件写入时出现错误 已记录日志\"}");
return;
}
}
context.Response.Write("{\"state\":\"success\",\"code\":0,\"msg\":\""+keyHead+guid+"\"}"); }
catch (Exception e)
{
Util.LogHelper.Info(e.Message + e.StackTrace);
context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}");
}
} private void uploadPartialFile(HttpContext context) {
try
{
//检查目录
mkdirIfNoExit();
if (context.Request["date"] == null)
{
context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错 参数date(第一片上传时间)不能为空\"}");
return;
}
DateTime uploadData;
if (!DateTime.TryParse(context.Request["date"], out uploadData))
{ context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错date参数错误 格式 yyyy-MM-dd\"}");
return;
}
if (context.Request["guid"] == null || context.Request["guid"].Trim().Length != )
{
context.Response.Write("{\"state\":\"error\",\"code\":-3,\"msg\":\"接口调用出错 guid(文件唯一标示)不能为空且必须为32位长度\"}");
return;
} if (context.Request["id"] == null || context.Request["id"].Trim().Length == )
{
context.Response.Write("{\"state\":\"error\",\"code\":-4,\"msg\":\"接口调用出错 id(文件分组id)不能为空\"}");
return;
}
int id = -;
if (!int.TryParse(context.Request["id"], out id))
{
context.Response.Write("{\"state\":\"error\",\"code\":-5,\"msg\":\"接口调用出错 id(文件分组id)必须为数字\"}");
return;
} if (context.Request.Files == null || context.Request.Files.Count == || context.Request.Files[].InputStream.Length == )
{
context.Response.Write("{\"state\":\"error\",\"code\":-6,\"msg\":\"接口调用出错 上传文件不能为空\"}");
return;
}
if (context.Request.Files.Count > )
{
context.Response.Write("{\"state\":\"error\",\"code\":-7,\"msg\":\"接口调用出错 每次只能上传单个文件\"}");
return;
}
string guid = context.Request["guid"].Trim();
string keyHead = uploadData.Year + "" + uploadData.Month + uploadData.Day;
string currentPath = getCurrentPathByDate(keyHead);
string filePath = getCurrentFilePathByDate(keyHead, guid, id);
if (File.Exists(filePath))
{
context.Response.Write("{\"state\":\"error\",\"code\":-8,\"msg\":\"接口调用出错 guid为" + guid + "文件id为" + id + "的文件已存在\"}");
return;
}
lock (filePath)
{
if (File.Exists(filePath))
{
context.Response.Write("{\"state\":\"error\",\"code\":-8,\"msg\":\" guid为" + guid + "文件id为" + id + "的文件已存在\"}");
return;
}
//创建文件
try
{
context.Request.Files[].SaveAs(filePath); }
catch (Exception e)
{
Util.LogHelper.Info(e.Message + e.StackTrace); context.Response.Write("{\"state\":\"error\",\"code\":-9,\"msg\":\"接口调用出错 guid为" + guid + "文件id为" + id + "的文件写入时出现错误 已记录日志\"}");
return;
}
} context.Response.Write("{\"state\":\"success\",\"code\":0,\"msg\":\" guid为" + guid + "文件id为" + id + "的文件写入成功\"}"); }
catch (Exception e)
{
Util.LogHelper.Info(e.Message + e.StackTrace);
context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}");
}
} private void joinfile(HttpContext context)
{
try
{
//检查目录
if (context.Request["date"] == null)
{
context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错 参数date(第一片上传时间)不能为空\"}");
return;
}
if (context.Request["guid"] == null || context.Request["guid"].Trim().Length != )
{
context.Response.Write("{\"state\":\"error\",\"code\":-3,\"msg\":\"接口调用出错 guid(文件唯一标示)不能为空且必须为32位长度\"}");
return;
} if (context.Request["idArray"] == null || context.Request["idArray"].Trim().Length == )
{
context.Response.Write("{\"state\":\"error\",\"code\":-4,\"msg\":\"接口调用出错 id(文件分组id列表)不能为空\"}");
return;
}
DateTime uploadData;
if (!DateTime.TryParse(context.Request["date"],out uploadData)) { context.Response.Write("{\"state\":\"error\",\"code\":-6,\"msg\":\"接口调用出错date参数错误 格式 yyyy-MM-dd\"}");
return;
} string keyHead = uploadData.Year + "" + uploadData.Month + uploadData.Day;
string guid = context.Request["guid"].Trim(); List<int> IdArray = context.Request["idArray"].StringArrayConvertInt(',').OrderBy(u=>u).ToList();
//开始检查文件是否全部存在
List<string> pathList = new List<string>();
if (IdArray.Count < )
{
context.Response.Write("{\"state\":\"error\",\"code\":-8,\"msg\":\"接口调用出错文件列表文件少于2个无法进行合并操作 请检查IdArray参数\"}");
return;
}
foreach (var item in IdArray)
{
string path = getCurrentFilePathByDate(keyHead,guid,item);
if (!File.Exists(path))
{
context.Response.Write("{\"state\":\"error\",\"code\":-7,\"msg\":\"id编号为"+item+"的文件在服务器上不存在 请检查\"}");
return;
}
pathList.Add(path); }
string newGuid = Guid.NewGuid().ToString();
string newFilePath = getNewFilePathByDate(keyHead,newGuid);
using (System.IO.FileStream fileStram = File.Open(newFilePath, FileMode.Create,FileAccess.Write))
{ //开始合并文件 创建一个副本
pathList.ForEach(u =>
{
//读取文件
using (FileStream save = new FileStream(u, FileMode.Open, FileAccess.Read))
{
byte[] bt = new byte[];
int count = -;
while ((count = save.Read(bt, , bt.Length)) > )
{
fileStram.Write(bt, , count);
}
} });
context.Response.Write("{\"state\":\"success\",\"code\":0,\"msg\":\""+ keyHead + newGuid + "\"}");
//删除文件列表
delFile(pathList);
} }
catch (Exception e)
{
Util.LogHelper.Info(e.Message + e.StackTrace);
context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}");
}
}
public bool IsReusable
{
get
{
return false;
}
}
public static void delFile(List<string> pathList) {
try
{ for (int i = ; i < pathList.Count; i++)
{
File.Delete(pathList[i].Replace("\\","/"));
}
}
catch (Exception e)
{
Util.LogHelper.Info("删除分片文件错误"+e.Message+e.StackTrace);
}
} /// <summary>
/// 创建部分文件集合
/// </summary>
/// <param name="context"></param>
public void ProcessRequest(HttpContext context)
{
try
{ context.Response.ContentType = "application/json"; string mode = context.Request["mode"].ToLower();
if (mode == "partialfile")
uploadPartialFile(context);
else if (mode == "joinfile")
joinfile(context);
else if (mode == "uploadfile")
uploadFile(context);
else
context.Response.Write("{\"state\":\"error\",\"code\":-10,\"msg\":\"接口调用出错 mode值范围为partialfile(上传分片文件)joinfile(合并分片文件)uploadfile上传单个文件 三种 \"}"); } catch (Exception e)
{ Util.LogHelper.Info("ProcessRequest执行错误" + e.Message + e.StackTrace);
context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}"); }
} }
}

js调用

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
<script src="https://cdn.bootcss.com/jquery.form/3.51/jquery.form.js"></script>
<form id="fileUpLoad" action="/UpLoadPartialFile.ashx?mode=partialfile" method="post" name="test">
<input type="file" name="name" onchange="upload(this)" />上传分片文件
<input type="hidden" id="guid" name="guid"value="aaaaaaaaaaaaaaaa" />
<input type="hidden" name="date" value="2017-10-02" />
<input type="hidden" id="id" name="id" value="0" /> </form> <form id="fileUpLoadFile" action="/UpLoadPartialFile.ashx?mode=uploadfile" method="post" name="test">
<input type="file" name="name2" onchange="uploadFile(this)" />上传单个文件 </form>
<input type="text" id="fileType" name="fileType" placeholder="合并的文件后缀名称 可选(合并文件时有效)" value="mp4" />
<button onclick="joinFIle()">合并文件</button> </body>
</html> <script> function newGuid() {
var guid = "";
for (var i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
guid += n; }
return guid;
}
var idArray = '';
var date = 2017-10-02;
var i = 0;
var guid = newGuid();
$('#guid').val(guid);
function joinFIle() { $.ajax('/UpLoadPartialFile.ashx?mode=joinfile&date=2017-10-02&guid=' + guid + '&idArray=' + idArray + '&fileType=' + $('#fileType').val()).done(function (rs) {
alert(rs.msg);
}) }
function upload(obj) { if (obj.size == 0)
return;
//上传表单
$('#id').val(++i);
idArray += i+',';
$('#fileUpLoad').ajaxSubmit(); } function uploadFile() {
$('#fileUpLoadFile').ajaxSubmit();
}
</script>

C#调用

        private static void post1()
{
string url = @"http://localhost:1128/uploadPartialFile.ashx?mode=partialfile&date=2017-10-03&id=1&guid=5ed1eddf7e7213ed0db6d5150b488335";//这里就不暴露我们的地址啦
string modelId = "4f1e2e3d-6231-4b13-96a4-835e5af10394";
string updateTime = "2016-11-03 14:17:25";
string encrypt = "f933797503d6e2c36762428a280e0559"; string filePath = @"D:/test2";
string fileName = "test2";
byte[] fileContentByte = new byte[1024]; // 文件内容二进制 #region 将文件转成二进制 FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
fileContentByte = new byte[fs.Length]; // 二进制文件
fs.Read(fileContentByte, 0, Convert.ToInt32(fs.Length));
fs.Close(); #endregion #region 定义请求体中的内容 并转成二进制 string boundary = "ceshi";
string Enter = "\r\n"; string modelIdStr = "--" + boundary + Enter
+ "Content-Disposition: form-data; name=\"modelId\"" + Enter + Enter
+ modelId + Enter; string fileContentStr = "--" + boundary + Enter
+ "Content-Type:application/octet-stream" + Enter
+ "Content-Disposition: form-data; name=\"fileContent\"; filename=\"" + fileName + "\"" + Enter + Enter; string updateTimeStr = Enter + "--" + boundary + Enter
+ "Content-Disposition: form-data; name=\"updateTime\"" + Enter + Enter
+ updateTime; string encryptStr = Enter + "--" + boundary + Enter
+ "Content-Disposition: form-data; name=\"encrypt\"" + Enter + Enter
+ encrypt + Enter + "--" + boundary + "--"; var modelIdStrByte = Encoding.UTF8.GetBytes(modelIdStr);//modelId所有字符串二进制 var fileContentStrByte = Encoding.UTF8.GetBytes(fileContentStr);//fileContent一些名称等信息的二进制(不包含文件本身) var updateTimeStrByte = Encoding.UTF8.GetBytes(updateTimeStr);//updateTime所有字符串二进制 var encryptStrByte = Encoding.UTF8.GetBytes(encryptStr);//encrypt所有字符串二进制 #endregion HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "multipart/form-data;boundary=" + boundary; Stream myRequestStream = request.GetRequestStream();//定义请求流 #region 将各个二进制 安顺序写入请求流 modelIdStr -> (fileContentStr + fileContent) -> uodateTimeStr -> encryptStr myRequestStream.Write(modelIdStrByte, 0, modelIdStrByte.Length); myRequestStream.Write(fileContentStrByte, 0, fileContentStrByte.Length);
myRequestStream.Write(fileContentByte, 0, fileContentByte.Length); myRequestStream.Write(updateTimeStrByte, 0, updateTimeStrByte.Length); myRequestStream.Write(encryptStrByte, 0, encryptStrByte.Length); #endregion HttpWebResponse response = (HttpWebResponse)request.GetResponse();//发送 Stream myResponseStream = response.GetResponseStream();//获取返回值
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); string retString = myStreamReader.ReadToEnd(); myStreamReader.Close();
myResponseStream.Close();
}

Code=0表示接口调用成功

其他情况下code为负数 msg中包含具体错误信息

单个分片文件上传不能超过4000kb

上传分片文件

http://localhost:1128/UpLoadPartialFile.ashx?mode=partialfile

method:post

参数

date 分片上传 参数格式yyyy-MM-dd日期 例如:     2017-10-02 所有分片上传都使用一个时间 服务端根据这个参数来区分文件夹

id  (整数) 分片文件编号 如1  服务端合并文件将根据编号由小到大排序合并

guid 客户端生成一个guid 后面所有同一个文件的分片均使用同一个guid

guid为32位长度 即省略-分隔符

浏览器js调用报文如下

调用成功返回json

{"state":"success","code":0,"msg":" guid为db334a03fc01b200c770871374734c7b文件id为1的文件写入成功"}

合并分片文件

http://localhost:1128/UpLoadPartialFile.ashx?mode=joinfile&date=2017-10-02&guid=db334a03fc01b200c770871374734c7b&idArray=1,2,&fileType=mp4

method :post

参数

date 分片上传时间(必选)

guid 上传分片时使用的guid (必选)

idArray 编号列表 拼接逗号分隔 需要两个以上 否则无法合并文件(必选)

filetype 文件后缀名称 可选 如果传递该参数 读取时也要传递 否则无法找到文件

调用成功返回

{"state":"success","code":0,"msg":"2017102cdb64b77-5f7c-4ccf-aa11-1e327dfcd49f"}

Msg中的字符串用于读取文件

上传单个文件

http://localhost:1128/UpLoadPartialFile.ashx?mode=uploadfile

method:post

文件流写入到请求中

调用成功返回

{"state":"success","code":0,"msg":"2017102cdb64b77-5f7c-4ccf-aa11-1e327dfcd49f"}

Msg中的字符串用于读取文件

安卓参考实现

http://blog.csdn.net/ylbf_dev/article/details/50468984

ios参考实现

http://www.jianshu.com/p/a0e3c77d3164

C#实现分片上传文件的更多相关文章

  1. django实现分片上传文件

    目标:利用django实现上传文件功能 1,先设置路由系统 urls.py from django.conf.urls import url,include from django.contrib i ...

  2. node.js分片上传文件

    前端 : <html> <head> <title>分片上传文件</title> </head> <body> <div ...

  3. WebUploader分片断点上传文件(二)

    写在前面: 这几天,有去研究一下WebUploader上传文件,前面的博客有记录下使用WebUploader简单上传文件的例子,今天就把分片断点上传的例子也记录下吧,在博客园中,也查看了一些资料,基本 ...

  4. Python之requests模块-大文件分片上传

    最近在做接口测试时,拿到一个分片上传文件的接口,http接口请求头中的Content-Type为multipart/form-data.需要在客户端将大文件分片成数据块后,依次传给服务端,由服务端还原 ...

  5. java下载网络大文件之内存不够的解决办法(包含分片上传分片下载)

    一.背景 2020年11月份的时候,我做过一个项目,涉及到网络文件,比如第三方接口提供一个文件的下载地址,使用java去下载,当时我全部加在到JVM内存里面,话说,单单是80M的下载单线程没问题,但是 ...

  6. java后端分片上传接口

    文件上传工具--FileUtil package com.youmejava.chun.util; import lombok.Data; import org.apache.tomcat.util. ...

  7. 用百度webuploader分片上传大文件

    一般在做文件上传的时候,都是通过客户端把要上传的文件上传到服务器,此时上传的文件都在服务器内存,如果上传的是视频等大文件,那么服务器内存就很紧张,而且一般我们都是用flash或者html5做异步上传, ...

  8. 打造 html5 文件上传组件,实现进度显示及拖拽上传,支持秒传+分片上传+断点续传,兼容IE6+及其它标准浏览器

    老早就注册了博客园帐号,昨天才发现,连博客都没开,Github也是一样,深觉惭愧,赶紧潜个水压压惊`(*∩_∩*)′ 言归正传.大概许多人都会用到文件上传的功能,上传的库貌似也不少,比如(jQuery ...

  9. 利用HTML5分片上传超大文件

    在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃:二是服务端配置复杂,要考虑接收超大表单和超时问题,如果是托管主机没准还改不了配置,默 ...

随机推荐

  1. Microcontroller measures resistance without an ADC

    Sensors automate most of the processes in industry. Most of these sensors, such as those for ammonia ...

  2. Caliburn.Micro对目录结构的要求

    Caliburn.Micro对MVVM目录结构的要求判定规则是如下正则表达式: (?<nsbefore>([A-Za-z_]\w*\.)*)(?<subns>ViewModel ...

  3. linux开放关闭防火墙端口

    原文:http://blog.csdn.net/fengspg/article/details/21337617 1) 重启后生效 开启: chkconfig iptables on 关闭: chkc ...

  4. Eclipse里web的依赖工程部署的简便方法

    用Eclipse开发项目,曾经为依赖工程的部署问题头疼过,用了MyEclipse之后就没有仔细去研究,最近研究了下,还真找到了比较简便的方法,之前都是采用Ant打jar包,copy到web工程,或者通 ...

  5. Python 列表(Lists)

    Python 列表(Lists) 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. Python有6个序列的内置类 ...

  6. The maximum number of processes for the user account running is currently , which can cause performance issues. We recommend increasing this to at least 4096.

    [root@localhost ~]# vi /etc/security/limits.conf # /etc/security/limits.conf # #Each line describes ...

  7. Arcgis license 服务无法启动的解决问题

    来自:http://blog.csdn.net/u013719339/article/details/51240312 1.检查服务开没开.打开资源管理器然后按照下面就出现了.也可以打开运行——ser ...

  8. DCI:DCI学习总结

    备注 之前把DCI的Role和四色原型的Role给弄混了,本文也不会比较这两种Role的区别(后面有机会再说),这里简单的记录一下对DCI的理解. 参考文章:http://www.cnblogs.co ...

  9. comgrid获取多选值

    var val = $('#cc').combobox('getValues');

  10. 最大的Redis集群:新浪Redis集群揭秘

    前言 Tape is Dead,Disk is Tape,Flash is Disk,RAM Locality is King.       — Jim Gray Redis不是比较成熟的Memcac ...