UploadFileHelper.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. using System.Net.Http;
  6. using System.Net.Http.Headers;
  7. using System.Threading;
  8. using Vinno.IUS.Common.Log;
  9. using Vinno.vCloud.Common.FIS.Storages;
  10. using Vinno.vCloud.Common.Storage.ObjectStorageInfo;
  11. namespace Vinno.vCloud.Common.FIS.Helper
  12. {
  13. internal class UploadFileHelper
  14. {
  15. /// <summary>上传文件</summary>
  16. /// <param name="fileData"></param>
  17. /// <param name="requestUrl"></param>
  18. /// <param name="authorization"></param>
  19. /// <returns></returns>
  20. public static Tuple<bool, string> UploadFile(string requestUrl, byte[] fileData, string mimeType, string authorization, Action<double> progressCallback = null, CancellationTokenSource cancelTokenSource = null)
  21. {
  22. var contentType = MediaTypeHeaderValue.Parse(mimeType);
  23. var requestHeads = new Dictionary<string, string>();
  24. ProductInfoHeaderValue productInfoHeaderValue = null;
  25. requestHeads.Add("Authorization", authorization);
  26. return UploadFile(fileData, contentType, requestUrl, requestHeads, productInfoHeaderValue, progressCallback, cancelTokenSource);
  27. }
  28. /// <summary>
  29. /// 上传文件
  30. /// </summary>
  31. /// <param name="requestUrl"></param>
  32. /// <param name="filePath"></param>
  33. /// <param name="mimeType"></param>
  34. /// <param name="authorization"></param>
  35. /// <param name="progressCallback"></param>
  36. /// <param name="cancelTokenSource"></param>
  37. /// <returns></returns>
  38. public static Tuple<bool, string> UploadFile(string requestUrl, string filePath, string mimeType, string authorization, Action<double> progressCallback = null, CancellationTokenSource cancelTokenSource = null)
  39. {
  40. var contentType = MediaTypeHeaderValue.Parse(mimeType);
  41. var requestHeads = new Dictionary<string, string>();
  42. ProductInfoHeaderValue productInfoHeaderValue = null;
  43. requestHeads.Add("Authorization", authorization);
  44. using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
  45. {
  46. byte[] buffer = new byte[fileStream.Length];
  47. fileStream.Read(buffer, 0, buffer.Length);
  48. return UploadFile(buffer, contentType, requestUrl, requestHeads, productInfoHeaderValue, progressCallback, cancelTokenSource);
  49. }
  50. }
  51. /// <summary>
  52. /// 上传文件(字节流)
  53. /// </summary>
  54. /// <param name="fileData"></param>
  55. /// <param name="mediaTypeHeaderValue"></param>
  56. /// <param name="requestUrl"></param>
  57. /// <param name="heads"></param>
  58. /// <param name="productInfoHeader"></param>
  59. /// <param name="progressCallback"></param>
  60. /// <param name="cancelTokenSource"></param>
  61. /// <returns></returns>
  62. /// <exception cref="Exception"></exception>
  63. private static Tuple<bool, string> UploadFile(byte[] fileData, MediaTypeHeaderValue mediaTypeHeaderValue, string requestUrl, Dictionary<string, string> heads, ProductInfoHeaderValue productInfoHeader, Action<double> progressCallback = null, CancellationTokenSource cancelTokenSource = null)
  64. {
  65. if (fileData == null || fileData.Length == 0)
  66. {
  67. throw new Exception("FileData is empty");
  68. }
  69. using (var request = new HttpRequestMessage())
  70. {
  71. using (var content = new UploadContent(fileData, mediaTypeHeaderValue))
  72. {
  73. content.ProgressChanged += (sender, progress) => { progressCallback?.Invoke((double)progress / 100); };
  74. request.RequestUri = new Uri(requestUrl);
  75. request.Method = HttpMethod.Put;
  76. request.Content = content;
  77. if (productInfoHeader != null)
  78. {
  79. request.Headers.UserAgent.Add(productInfoHeader);
  80. }
  81. foreach (var head in heads)
  82. {
  83. request.Headers.TryAddWithoutValidation(head.Key, head.Value);
  84. }
  85. return HttpClientHelper.ExecuteRequest(request, GetUploadResult, false, cancelTokenSource);
  86. }
  87. }
  88. }
  89. private static Tuple<bool, string> GetUploadResult(HttpResponseMessage response)
  90. {
  91. if (response != null && response.StatusCode == HttpStatusCode.OK)
  92. {
  93. return new Tuple<bool, string>(true, response.Headers?.ETag?.Tag ?? string.Empty);
  94. }
  95. Logger.WriteLineError($"GetUploadResult Failed, StatusCode: {response?.StatusCode}");
  96. return new Tuple<bool, string>(false, "");
  97. }
  98. /// <summary>
  99. /// 分块读取文件,若文件大于500MB,则每次只读500MB
  100. /// </summary>
  101. internal static FlieSpliceInfo ReadFileData(string filePath, long manualDivisionForUpload, int offsetCount)
  102. {
  103. bool isReadAllBytes = false;
  104. var dic = new Dictionary<int, byte[]>();
  105. using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
  106. {
  107. var partCount = (int)((fs.Length / manualDivisionForUpload) + (fs.Length % manualDivisionForUpload > 0 ? 1 : 0));
  108. if (partCount > 1)
  109. {
  110. var spliceSize = 500 * 1024 * 1024;
  111. int spliceCount = 0;
  112. if (fs.Length > spliceSize)//每次只读500M
  113. {
  114. long offsetSize = manualDivisionForUpload * offsetCount;
  115. var restSize = fs.Length - offsetSize;
  116. if (restSize > spliceSize)
  117. {
  118. byte[] btArr = new byte[spliceSize];
  119. fs.Seek(offsetSize, SeekOrigin.Begin);
  120. fs.Read(btArr, 0, btArr.Length);
  121. spliceCount = (int)(spliceSize / manualDivisionForUpload) + (spliceSize % manualDivisionForUpload > 0 ? 1 : 0);
  122. long offsetIndex = 0;
  123. for (var i = 0; i < spliceCount; i++)
  124. {
  125. var tempLength = manualDivisionForUpload;
  126. var tempByte = new byte[tempLength];
  127. offsetIndex = i * manualDivisionForUpload;
  128. Array.Copy(btArr, offsetIndex, tempByte, 0, tempByte.Length);
  129. dic.Add(i + offsetCount, tempByte);
  130. }
  131. }
  132. else
  133. {
  134. byte[] btArr = new byte[restSize];
  135. fs.Seek(offsetSize, SeekOrigin.Begin);
  136. fs.Read(btArr, 0, btArr.Length);
  137. spliceCount = (int)(restSize / manualDivisionForUpload) + (restSize % manualDivisionForUpload > 0 ? 1 : 0);
  138. long offsetIndex = 0;
  139. for (var i = 0; i < spliceCount; i++)
  140. {
  141. var tempLength = manualDivisionForUpload;
  142. if (spliceCount - 1 == i)
  143. {
  144. //最后一个分块File
  145. tempLength = btArr.Length - (spliceCount - 1) * manualDivisionForUpload;
  146. isReadAllBytes = true;
  147. }
  148. var tempByte = new byte[tempLength];
  149. offsetIndex = i * manualDivisionForUpload;
  150. Array.Copy(btArr, offsetIndex, tempByte, 0, tempByte.Length);
  151. dic.Add(i + offsetCount, tempByte);
  152. }
  153. }
  154. }
  155. else
  156. {
  157. //读取文件
  158. byte[] btArr = new byte[fs.Length];
  159. fs.Read(btArr, 0, btArr.Length);
  160. if (partCount > 1)
  161. {
  162. long offsetIndex = 0;
  163. for (var i = 0; i < partCount; i++)
  164. {
  165. var tempLength = manualDivisionForUpload;
  166. if (partCount - 1 == i)
  167. {
  168. //最后一个分块File
  169. tempLength = btArr.Length - (partCount - 1) * manualDivisionForUpload;
  170. isReadAllBytes = true;
  171. }
  172. var tempByte = new byte[tempLength];
  173. offsetIndex = i * manualDivisionForUpload;
  174. Array.Copy(btArr, offsetIndex, tempByte, 0, tempByte.Length);
  175. dic.Add(i, tempByte);
  176. }
  177. }
  178. }
  179. }
  180. else
  181. {
  182. byte[] btArr = new byte[fs.Length];
  183. fs.Read(btArr, 0, btArr.Length);
  184. dic.Add(0, btArr);
  185. isReadAllBytes = true;
  186. }
  187. return new FlieSpliceInfo(partCount, dic, isReadAllBytes);
  188. }
  189. }
  190. /// <summary>
  191. /// 分块读取文件
  192. /// </summary>
  193. internal static Dictionary<int, byte[]> ReadFileData(string filePath, long manualDivisionForUpload)
  194. {
  195. var dic = new Dictionary<int, byte[]>();
  196. using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
  197. {
  198. var partCount = (int)((fs.Length / manualDivisionForUpload) + (fs.Length % manualDivisionForUpload > 0 ? 1 : 0));
  199. //大于1.7G的问题,用分块读取File
  200. if (fs.Length > 1782579200)
  201. {
  202. var byteSize = 10;
  203. byte[] buffer = new byte[byteSize * 1024 * 1024];//10M的缓冲byte
  204. int fileCursor = 0;
  205. int readerCursor = 0;
  206. var splitFileTimes = manualDivisionForUpload / buffer.Length + (manualDivisionForUpload % buffer.Length > 0 ? 1 : 0);
  207. var fileSplitFileTimes = fs.Length / buffer.Length + (fs.Length % buffer.Length > 0 ? 1 : 0);
  208. if (fileSplitFileTimes < splitFileTimes)
  209. {
  210. splitFileTimes = fileSplitFileTimes;
  211. }
  212. //超过200就不能读取了,会溢出
  213. if (splitFileTimes > 200)
  214. {
  215. return dic;
  216. }
  217. NextFileBegin:
  218. using (MemoryStream ms = new MemoryStream())
  219. {
  220. int readLength = 0;
  221. while ((readLength = fs.Read(buffer, 0, buffer.Length)) > 0)
  222. {
  223. readerCursor++;
  224. ms.Write(buffer, 0, readLength);
  225. if (readerCursor >= splitFileTimes)
  226. {
  227. var allBytes = ms.ToArray();
  228. dic.Add(fileCursor, allBytes);
  229. readerCursor = 0;
  230. fileCursor++;
  231. break;
  232. }
  233. else
  234. {
  235. if (readLength < buffer.Length && readerCursor > 0 && readerCursor < splitFileTimes)
  236. {
  237. //表示最后一个了
  238. var allBytes = ms.ToArray();
  239. dic.Add(fileCursor, allBytes);
  240. readerCursor = 0;
  241. fileCursor++;
  242. break;
  243. }
  244. }
  245. }
  246. }
  247. if (fileCursor < partCount)
  248. {
  249. goto NextFileBegin;
  250. }
  251. }
  252. else
  253. {
  254. //读取文件
  255. byte[] btArr = new byte[fs.Length];
  256. fs.Read(btArr, 0, btArr.Length);
  257. if (partCount > 1)
  258. {
  259. long offsetIndex = 0;
  260. for (var i = 0; i < partCount; i++)
  261. {
  262. var tempLength = manualDivisionForUpload;
  263. if (partCount - 1 == i)
  264. {
  265. //最后一个分块File
  266. tempLength = btArr.Length - (partCount - 1) * manualDivisionForUpload;
  267. }
  268. var tempByte = new byte[tempLength];
  269. offsetIndex = i * manualDivisionForUpload;
  270. Array.Copy(btArr, offsetIndex, tempByte, 0, tempByte.Length);
  271. dic.Add(i, tempByte);
  272. }
  273. }
  274. else
  275. {
  276. dic.Add(0, btArr);
  277. }
  278. }
  279. }
  280. return dic;
  281. }
  282. }
  283. }