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. SilverLight学习笔记--使用WebClient实现通讯(一)(上传和下载字符串数据)

    一.什么是WebClient类   1.基本知识    WebClient类是Mircsoft在.NET框架下提供的向 URI 标识的资源发送数据和从 URI 标识的资源接收数据的公共方法.通过这个类 ...

  2. SpringMvc(1) --Eclipse搭建web项目

    http://blog.csdn.net/uucai http://blog.csdn.net/uucai/article/details/21258575

  3. Qt Creator的下载、安装及试用

    1.试用环境及版本介绍:本文介绍的是windows桌面平台下使用Qt4.7.2和Qt Creator2.1.0,其他操作系统和版本在阅读时请留意. 2.下载: 从http://get.qt.nokia ...

  4. iOS8 NotificationCenter Extension 简介

    在最新的WWDC14上面,苹果发布了iOS8的一些新特性,而其中最让程序员兴奋的特性莫过于Extension,或者称之为Widget. 下面就来尝鲜试验一把. 一.Extension简介 首先,苹果只 ...

  5. SpringMVC整合fastjson、easyui 乱码问题

    一.框架版本 SpringMVC:3.1.1.RELEASE fastjson:1.2.7 easyui :1.4.5 二.乱码现象    Action中使用@ResponseBody返回Json数据 ...

  6. Visual Studio 2012连接TFS2010登录不了

    一直用VS2012+TFS2010开发项目, 最近几天忽然很不正常, 在VS中会频繁要求输入TFS的账号密码, 经常要输入很多遍才可以正常连接签入签出. 这几天更甚, 基本上直接连接不了了. 网上找到 ...

  7. 运行Hadoop的示例程序WordCount-Running Hadoop Example

      In the last post we've installed Hadoop 2.2.0 on Ubuntu. Now we'll see how to launch an example ma ...

  8. Jni的Jclass JmethodID JfrieldID的差异

    Jni的Jclass JmethodID JfrieldID 这三者都是java类别的属性,本质上都是指标(Pointer).透过这些指标就能快速调用java类别的函数,或存取对象的属性值.在该类别被 ...

  9. 不同版本(2.3,2.4,2.5,3.0)的Servlet web.xml 头信息

    不同版本(2.3,2.4,2.5,3.0)的Servlet web.xml 头信息 学习了:https://blog.csdn.net/z69183787/article/details/360080 ...

  10. RS请求错误之RSV-BBP-0028

    环境:Version  Cognos10.2 单机 非集群 运行报表的时候经常遇到: 错误信息为: The secondary request failed. The requested sessio ...