标签:摘要 parse upload host 定义 catch roc ajax 后缀
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.IO; 6 using System.Configuration; 7 8 namespace WebApplication1 9 { 10 /// <summary> 11 /// PartialFileSet 的摘要说明 12 /// </summary> 13 public class UpLoadPartialFile : IHttpHandler 14 { 15 public static DateTime mkdirRecodeTime = DateTime.Now.AddDays(-2); 16 public static string keyHead = DateTime.Now.Year + "" + DateTime.Now.Month + DateTime.Now.Day; 17 public static string path = ConfigurationManager.AppSettings["filePath"].ToString(); 18 public static object mkdirLock = new object(); 19 20 /// <summary> 21 /// 根据日期字符串返回路径 22 /// </summary> 23 /// <param name="keyHead">日期字符串yyyyMMdd</param> 24 /// <returns></returns> 25 private static string getCurrentPathByDate(string keyHead) 26 { 27 28 return path + "\\" + keyHead; 29 } 30 31 private static string getCurrentFilePathByDate(string keyHead, string guid, int id) 32 { 33 return getCurrentPathByDate(keyHead) + "\\" + guid + id; 34 } 35 36 private static string getNewFilePathByDate(string keyHead, string guid) 37 { 38 string fileType = HttpContext.Current.Request["fileType"]; 39 if(fileType!=null&& fileType.Length>0) 40 return getCurrentPathByDate(keyHead) + "\\" + guid+"."+fileType; 41 return getCurrentPathByDate(keyHead) + "\\" + guid; 42 } 43 /// <summary> 44 /// 如果目标文件夹不存在 创建文件夹 45 /// </summary> 46 /// <param name="keyHead"></param> 47 private static void mkdirIfNoExit() 48 { 49 50 if ((DateTime.Now-mkdirRecodeTime ).Days < 1) 51 return; 52 53 //创建文件夹目录 54 if (Directory.Exists(getCurrentPathByDate(keyHead))) 55 return; 56 lock (mkdirLock) 57 { 58 59 if (!Directory.Exists(path)) 60 Directory.CreateDirectory(path); 61 if (!Directory.Exists(getCurrentPathByDate(keyHead))) 62 Directory.CreateDirectory(getCurrentPathByDate(keyHead)); 63 64 keyHead = DateTime.Now.Year + "" + DateTime.Now.Month + DateTime.Now.Day; 65 mkdirRecodeTime = DateTime.Now; 66 return; 67 } 68 69 } 70 71 private void uploadFile(HttpContext context) 72 { 73 try 74 { 75 //检查目录 76 mkdirIfNoExit(); 77 78 79 80 if (context.Request.Files == null || context.Request.Files.Count == 0 || context.Request.Files[0].InputStream.Length == 0) 81 { 82 context.Response.Write("{\"state\":\"error\",\"code\":-6,\"msg\":\"接口调用出错 上传文件不能为空\"}"); 83 return; 84 } 85 if (context.Request.Files.Count > 1) 86 { 87 context.Response.Write("{\"state\":\"error\",\"code\":-7,\"msg\":\"接口调用出错 每次只能上传单个文件\"}"); 88 return; 89 } 90 string guid = Guid.NewGuid().ToString(); 91 92 string keyHead = DateTime.Now.Year + "" + DateTime.Now.Month + DateTime.Now.Day; 93 string currentPath = getCurrentPathByDate(keyHead); 94 string filePath = getNewFilePathByDate(keyHead, guid); 95 96 lock (filePath) 97 { 98 //创建文件 99 try 100 { 101 context.Request.Files[0].SaveAs(filePath); 102 103 } 104 catch (Exception e) 105 { 106 Util.LogHelper.Info(e.Message + e.StackTrace); 107 108 context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错 guid为" + guid + "的文件写入时出现错误 已记录日志\"}"); 109 return; 110 } 111 } 112 context.Response.Write("{\"state\":\"success\",\"code\":0,\"msg\":\""+keyHead+guid+"\"}"); 113 114 } 115 catch (Exception e) 116 { 117 Util.LogHelper.Info(e.Message + e.StackTrace); 118 context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}"); 119 } 120 } 121 122 private void uploadPartialFile(HttpContext context) { 123 try 124 { 125 //检查目录 126 mkdirIfNoExit(); 127 if (context.Request["date"] == null) 128 { 129 context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错 参数date(第一片上传时间)不能为空\"}"); 130 return; 131 } 132 DateTime uploadData; 133 if (!DateTime.TryParse(context.Request["date"], out uploadData)) 134 { 135 136 context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错date参数错误 格式 yyyy-MM-dd\"}"); 137 return; 138 } 139 if (context.Request["guid"] == null || context.Request["guid"].Trim().Length != 32) 140 { 141 context.Response.Write("{\"state\":\"error\",\"code\":-3,\"msg\":\"接口调用出错 guid(文件唯一标示)不能为空且必须为32位长度\"}"); 142 return; 143 } 144 145 if (context.Request["id"] == null || context.Request["id"].Trim().Length == 0) 146 { 147 context.Response.Write("{\"state\":\"error\",\"code\":-4,\"msg\":\"接口调用出错 id(文件分组id)不能为空\"}"); 148 return; 149 } 150 int id = -1; 151 if (!int.TryParse(context.Request["id"], out id)) 152 { 153 context.Response.Write("{\"state\":\"error\",\"code\":-5,\"msg\":\"接口调用出错 id(文件分组id)必须为数字\"}"); 154 return; 155 } 156 157 158 if (context.Request.Files == null || context.Request.Files.Count == 0 || context.Request.Files[0].InputStream.Length == 0) 159 { 160 context.Response.Write("{\"state\":\"error\",\"code\":-6,\"msg\":\"接口调用出错 上传文件不能为空\"}"); 161 return; 162 } 163 if (context.Request.Files.Count > 1) 164 { 165 context.Response.Write("{\"state\":\"error\",\"code\":-7,\"msg\":\"接口调用出错 每次只能上传单个文件\"}"); 166 return; 167 } 168 string guid = context.Request["guid"].Trim(); 169 string keyHead = uploadData.Year + "" + uploadData.Month + uploadData.Day; 170 string currentPath = getCurrentPathByDate(keyHead); 171 string filePath = getCurrentFilePathByDate(keyHead, guid, id); 172 if (File.Exists(filePath)) 173 { 174 context.Response.Write("{\"state\":\"error\",\"code\":-8,\"msg\":\"接口调用出错 guid为" + guid + "文件id为" + id + "的文件已存在\"}"); 175 return; 176 } 177 lock (filePath) 178 { 179 if (File.Exists(filePath)) 180 { 181 context.Response.Write("{\"state\":\"error\",\"code\":-8,\"msg\":\" guid为" + guid + "文件id为" + id + "的文件已存在\"}"); 182 return; 183 } 184 //创建文件 185 try 186 { 187 context.Request.Files[0].SaveAs(filePath); 188 189 } 190 catch (Exception e) 191 { 192 Util.LogHelper.Info(e.Message + e.StackTrace); 193 194 context.Response.Write("{\"state\":\"error\",\"code\":-9,\"msg\":\"接口调用出错 guid为" + guid + "文件id为" + id + "的文件写入时出现错误 已记录日志\"}"); 195 return; 196 } 197 } 198 199 context.Response.Write("{\"state\":\"success\",\"code\":0,\"msg\":\" guid为" + guid + "文件id为" + id + "的文件写入成功\"}"); 200 201 } 202 catch (Exception e) 203 { 204 Util.LogHelper.Info(e.Message + e.StackTrace); 205 context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}"); 206 } 207 } 208 209 private void joinfile(HttpContext context) 210 { 211 try 212 { 213 //检查目录 214 if (context.Request["date"] == null) 215 { 216 context.Response.Write("{\"state\":\"error\",\"code\":-2,\"msg\":\"接口调用出错 参数date(第一片上传时间)不能为空\"}"); 217 return; 218 } 219 if (context.Request["guid"] == null || context.Request["guid"].Trim().Length != 32) 220 { 221 context.Response.Write("{\"state\":\"error\",\"code\":-3,\"msg\":\"接口调用出错 guid(文件唯一标示)不能为空且必须为32位长度\"}"); 222 return; 223 } 224 225 if (context.Request["idArray"] == null || context.Request["idArray"].Trim().Length == 0) 226 { 227 context.Response.Write("{\"state\":\"error\",\"code\":-4,\"msg\":\"接口调用出错 id(文件分组id列表)不能为空\"}"); 228 return; 229 } 230 DateTime uploadData; 231 if (!DateTime.TryParse(context.Request["date"],out uploadData)) { 232 233 context.Response.Write("{\"state\":\"error\",\"code\":-6,\"msg\":\"接口调用出错date参数错误 格式 yyyy-MM-dd\"}"); 234 return; 235 } 236 237 string keyHead = uploadData.Year + "" + uploadData.Month + uploadData.Day; 238 string guid = context.Request["guid"].Trim(); 239 240 List<int> IdArray = context.Request["idArray"].StringArrayConvertInt(‘,‘).OrderBy(u=>u).ToList(); 241 //开始检查文件是否全部存在 242 List<string> pathList = new List<string>(); 243 if (IdArray.Count < 1) 244 { 245 context.Response.Write("{\"state\":\"error\",\"code\":-8,\"msg\":\"接口调用出错文件列表文件少于2个无法进行合并操作 请检查IdArray参数\"}"); 246 return; 247 } 248 foreach (var item in IdArray) 249 { 250 string path = getCurrentFilePathByDate(keyHead,guid,item); 251 if (!File.Exists(path)) 252 { 253 context.Response.Write("{\"state\":\"error\",\"code\":-7,\"msg\":\"id编号为"+item+"的文件在服务器上不存在 请检查\"}"); 254 return; 255 } 256 pathList.Add(path); 257 258 } 259 string newGuid = Guid.NewGuid().ToString(); 260 string newFilePath = getNewFilePathByDate(keyHead,newGuid); 261 using (System.IO.FileStream fileStram = File.Open(newFilePath, FileMode.Create,FileAccess.Write)) 262 { 263 264 //开始合并文件 创建一个副本 265 pathList.ForEach(u => 266 { 267 //读取文件 268 using (FileStream save = new FileStream(u, FileMode.Open, FileAccess.Read)) 269 { 270 byte[] bt = new byte[1024]; 271 int count = -1; 272 while ((count = save.Read(bt, 0, bt.Length)) > 0) 273 { 274 fileStram.Write(bt, 0, count); 275 } 276 } 277 278 }); 279 context.Response.Write("{\"state\":\"success\",\"code\":0,\"msg\":\""+ keyHead + newGuid + "\"}"); 280 //删除文件列表 281 delFile(pathList); 282 } 283 284 } 285 catch (Exception e) 286 { 287 Util.LogHelper.Info(e.Message + e.StackTrace); 288 context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}"); 289 } 290 } 291 public bool IsReusable 292 { 293 get 294 { 295 return false; 296 } 297 } 298 public static void delFile(List<string> pathList) { 299 try 300 { 301 302 for (int i = 0; i < pathList.Count; i++) 303 { 304 File.Delete(pathList[i].Replace("\\","/")); 305 } 306 } 307 catch (Exception e) 308 { 309 Util.LogHelper.Info("删除分片文件错误"+e.Message+e.StackTrace); 310 } 311 } 312 313 /// <summary> 314 /// 创建部分文件集合 315 /// </summary> 316 /// <param name="context"></param> 317 public void ProcessRequest(HttpContext context) 318 { 319 try 320 { 321 322 323 context.Response.ContentType = "application/json"; 324 325 string mode = context.Request["mode"].ToLower(); 326 if (mode == "partialfile") 327 uploadPartialFile(context); 328 else if (mode == "joinfile") 329 joinfile(context); 330 else if (mode == "uploadfile") 331 uploadFile(context); 332 else 333 context.Response.Write("{\"state\":\"error\",\"code\":-10,\"msg\":\"接口调用出错 mode值范围为partialfile(上传分片文件)joinfile(合并分片文件)uploadfile上传单个文件 三种 \"}"); 334 335 } 336 337 catch (Exception e) 338 { 339 340 Util.LogHelper.Info("ProcessRequest执行错误" + e.Message + e.StackTrace); 341 context.Response.Write("{\"state\":\"error\",\"code\":-1,\"msg\":\"接口调用出错 已记录日志\"}"); 342 343 344 } 345 } 346 347 348 349 350 351 352 } 353 }
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为负数 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
标签:摘要 parse upload host 定义 catch roc ajax 后缀
原文地址:http://www.cnblogs.com/ProDoctor/p/7625268.html