C#实现分片上传文件
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的文件写入成功"}
合并分片文件
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#实现分片上传文件的更多相关文章
- django实现分片上传文件
目标:利用django实现上传文件功能 1,先设置路由系统 urls.py from django.conf.urls import url,include from django.contrib i ...
- node.js分片上传文件
前端 : <html> <head> <title>分片上传文件</title> </head> <body> <div ...
- WebUploader分片断点上传文件(二)
写在前面: 这几天,有去研究一下WebUploader上传文件,前面的博客有记录下使用WebUploader简单上传文件的例子,今天就把分片断点上传的例子也记录下吧,在博客园中,也查看了一些资料,基本 ...
- Python之requests模块-大文件分片上传
最近在做接口测试时,拿到一个分片上传文件的接口,http接口请求头中的Content-Type为multipart/form-data.需要在客户端将大文件分片成数据块后,依次传给服务端,由服务端还原 ...
- java下载网络大文件之内存不够的解决办法(包含分片上传分片下载)
一.背景 2020年11月份的时候,我做过一个项目,涉及到网络文件,比如第三方接口提供一个文件的下载地址,使用java去下载,当时我全部加在到JVM内存里面,话说,单单是80M的下载单线程没问题,但是 ...
- java后端分片上传接口
文件上传工具--FileUtil package com.youmejava.chun.util; import lombok.Data; import org.apache.tomcat.util. ...
- 用百度webuploader分片上传大文件
一般在做文件上传的时候,都是通过客户端把要上传的文件上传到服务器,此时上传的文件都在服务器内存,如果上传的是视频等大文件,那么服务器内存就很紧张,而且一般我们都是用flash或者html5做异步上传, ...
- 打造 html5 文件上传组件,实现进度显示及拖拽上传,支持秒传+分片上传+断点续传,兼容IE6+及其它标准浏览器
老早就注册了博客园帐号,昨天才发现,连博客都没开,Github也是一样,深觉惭愧,赶紧潜个水压压惊`(*∩_∩*)′ 言归正传.大概许多人都会用到文件上传的功能,上传的库貌似也不少,比如(jQuery ...
- 利用HTML5分片上传超大文件
在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃:二是服务端配置复杂,要考虑接收超大表单和超时问题,如果是托管主机没准还改不了配置,默 ...
随机推荐
- CentOS 6.9/7通过yum安装指定版本的PostgreSQL
PostgreSQL(10+) 一.安装PostgreSQL // 安装EPEL源 # wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel- ...
- <摘录>CentOS6.5下添加epel源
0.安装yum优先级插件 yum install yum-priorities 1.epel简介: https://fedoraproject.org/wiki/EPEL/zh-cn rpm -Uvh ...
- The Eclipse runtime options
Version 3.6 - Last revised August 5, 2009 The Eclipse platform is highly configurable. Configuration ...
- 无线遥控检测仪 A890-RES
本产品为无线遥控接收器发射器的生产调试项目开发而设计,能自动识别接收并显示遥控器的所有信息:频率.芯片类型.周期.地址码.数据码,并能自动计算振荡阻值,35组自动保存.315M.433M 双频同时待机 ...
- springMvc 的参数验证 BindingResult result 的使用
http://blog.sina.com.cn/s/blog_6829be5c0101alxh.html 非常详细的一篇讲解 并且值得深入探讨 http://bbs.csdn.NET/topics/3 ...
- android 高清壁纸设置慢
由于项目的需要最近在解决一个 bug 在1080p 的手机上面设置壁纸会很慢慢,慢的原因是和壁纸 的大小 有关,壁纸越大,时间直越长,一般1080 p 的壁纸大概有10M左右, 所以通过文件流 来保 ...
- Eclipse maven构建springmvc项目
原文地址: http://www.cnblogs.com/fangjins/archive/2012/05/06/2485459.html 一.背景介绍 对于初学者,用maven构建项目并不是一件容易 ...
- 什么是进程And线程
原创 2015年02月01日 11:49:01 学习.net 时遇到了两个新词汇:进程和线程.书上的太深奥,就查了查资料,整合下,希望对大家有帮助. [比喻]:用手去抓苹果,很显然一根手指是不行, ...
- 🌅 使用 Dawn 快速搭建 React 项目!
开发一个 React 项目,通常避免不了要去配置 Webpack 和 babel 之类,以支持 commonjs 或 es 模块及各种 es 新语法,及进行 jsx 语法的转义.当然也可以用 crea ...
- Java程序猿笔试面试之String4
怎样删除String中反复的字符good? 思想一:蛮力法,进行双重循环,此算法的复杂度为O(n^2),n是指字符串的长度 public class RemoveSameChar { public s ...