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. Java容器-引用分类与部分Map用法

    目录 1.引用分类 2.了解WeakHashMap.IdentityHashMap.EnumMap 3.同步控制与只读设置 代码实现 1.引用分类(面试) 强引用(StrongReference):引 ...

  2. How to implement *All-Digital* analog-to-digital converters in FPGAs and ASICs

    When we engineers look at the complexity of system design these days, we are challenged with crammin ...

  3. Time Step Too Small in Multisim

    http://digital.ni.com/public.nsf/allkb/4B99B2CD6C0C3B6A86257205005D58E0 Error: Time Step Too Small i ...

  4. [翻译] Blocks and Variables

    Blocks and Variables https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/A ...

  5. javacc学习总结

    在学javacc的时候.发现一个问题,见下: Example.jj文件 PARSER_BEGIN(Example) public class Example { public static void ...

  6. 《jQuery技术内幕:深入解析jQuery架构设计与实现原理》

    <jQuery技术内幕:深入解析jQuery架构设计与实现原理> 基本信息 作者: 高云 出版社:机械工业出版社 ISBN:9787111440826 上架时间:2014-1-10 出版日 ...

  7. Node 多进程并发控制小模块 - lockman

    介绍 lockman 是一个用于多进程的并发控制锁, 类似一些语言中(比如 C#)的 lock 关键字可以用来确保代码块完成运行,而不会被其他进程中断.它可以把一段代码定义为互斥段(critical ...

  8. [android] Activity 的生命周期 以及横屏竖屏切换时 Activity 的状态变化

    生命周期Android 系统在Activity 生命周期中加入一些钩子,我们可以在这些系统预留的钩子中做一些事情.例举了 7 个常用的钩子:protected void onCreate(Bundle ...

  9. #include &lt;NOIP2009 Junior&gt; 细胞分裂 ——using namespace wxl;

    题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家.现在,他正在为一个细胞实 验做准备工作:培养细胞样本. Hanks 博士手里现在有 N 种细胞,编号从 1~N,一个 ...

  10. 挑战黑客极限:Pwn2Own 2015成史上“最难”黑客大赛

    Pwn2Own是全球最著名.奖金最丰厚的黑客大赛,由美国五角大楼入侵防护系统供应商TippingPoint赞助.近日Pwn2Own 2015公布全新的比赛规则,本届赛事难度超高.史无前例,包括VUPE ...