FileExt.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.IO;
  3. using System.Threading.Tasks;
  4. namespace Masuit.Tools.Files
  5. {
  6. /// <summary>
  7. /// 大文件操作扩展类
  8. /// </summary>
  9. public static class FileExt
  10. {
  11. /// <summary>
  12. /// 以文件流的形式复制大文件
  13. /// </summary>
  14. /// <param name="fs">源</param>
  15. /// <param name="dest">目标地址</param>
  16. /// <param name="bufferSize">缓冲区大小,默认8MB</param>
  17. public static void CopyToFile(this Stream fs, string dest, int bufferSize = 1024 * 8 * 1024)
  18. {
  19. using (FileStream fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite))
  20. {
  21. byte[] buf = new byte[bufferSize];
  22. int len = 0;
  23. while ((len = fs.Read(buf, 0, buf.Length)) != 0)
  24. {
  25. fsWrite.Write(buf, 0, len);
  26. }
  27. }
  28. }
  29. /// <summary>
  30. /// 以文件流的形式复制大文件(异步方式)
  31. /// </summary>
  32. /// <param name="fs">源</param>
  33. /// <param name="dest">目标地址</param>
  34. /// <param name="bufferSize">缓冲区大小,默认8MB</param>
  35. public static async void CopyToFileAsync(this Stream fs, string dest, int bufferSize = 1024 * 1024 * 8)
  36. {
  37. using (FileStream fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite))
  38. {
  39. byte[] buf = new byte[bufferSize];
  40. int len;
  41. await Task.Run(() =>
  42. {
  43. using (fs)
  44. {
  45. while ((len = fs.Read(buf, 0, buf.Length)) != 0)
  46. {
  47. fsWrite.Write(buf, 0, len);
  48. }
  49. }
  50. }).ConfigureAwait(true);
  51. }
  52. }
  53. /// <summary>
  54. /// 计算文件的 MD5 值
  55. /// </summary>
  56. /// <param name="fs">源文件流</param>
  57. /// <returns>MD5 值16进制字符串</returns>
  58. public static string GetFileMD5(this FileStream fs) => HashFile(fs, "md5");
  59. /// <summary>
  60. /// 计算文件的 MD5 值
  61. /// </summary>
  62. /// <param name="fs">源文件流</param>
  63. /// <returns>MD5 值16进制字符串</returns>
  64. public static Task<string> GetFileMD5Async(this FileStream fs) => HashFileAsync(fs, "md5");
  65. /// <summary>
  66. /// 计算文件的 sha1 值
  67. /// </summary>
  68. /// <param name="fs">源文件流</param>
  69. /// <returns>sha1 值16进制字符串</returns>
  70. public static string GetFileSha1(this Stream fs) => HashFile(fs, "sha1");
  71. /// <summary>
  72. /// 计算文件的 sha1 值
  73. /// </summary>
  74. /// <param name="fs">源文件流</param>
  75. /// <returns>sha1 值16进制字符串</returns>
  76. public static Task<string> GetFileSha1Async(this FileStream fs) => HashFileAsync(fs, "sha1");
  77. /// <summary>
  78. /// 计算文件的哈希值
  79. /// </summary>
  80. /// <param name="fs">被操作的源数据流</param>
  81. /// <param name="algName">算法:sha1,md5</param>
  82. /// <returns>哈希值16进制字符串</returns>
  83. private static string HashFile(Stream fs, string algName)
  84. {
  85. byte[] hashBytes = HashData(fs, algName);
  86. return ByteArrayToHexString(hashBytes);
  87. }
  88. /// <summary>
  89. /// 计算文件的哈希值
  90. /// </summary>
  91. /// <param name="fs">被操作的源数据流</param>
  92. /// <param name="algName">算法:sha1,md5</param>
  93. /// <returns>哈希值16进制字符串</returns>
  94. private static async Task<string> HashFileAsync(Stream fs, string algName)
  95. {
  96. byte[] hashBytes = await HashDataAsync(fs, algName).ConfigureAwait(false);
  97. return ByteArrayToHexString(hashBytes);
  98. }
  99. /// <summary>
  100. /// 计算哈希值
  101. /// </summary>
  102. /// <param name="stream">要计算哈希值的 Stream</param>
  103. /// <param name="algName">算法:sha1,md5</param>
  104. /// <returns>哈希值字节数组</returns>
  105. private static byte[] HashData(System.IO.Stream stream, string algName)
  106. {
  107. System.Security.Cryptography.HashAlgorithm algorithm;
  108. if (algName == null)
  109. {
  110. throw new ArgumentNullException("algName 不能为 null");
  111. }
  112. if (string.Compare(algName, "sha1", true) == 0)
  113. {
  114. algorithm = System.Security.Cryptography.SHA1.Create();
  115. }
  116. else
  117. {
  118. if (string.Compare(algName, "md5", true) != 0)
  119. {
  120. throw new Exception("algName 只能使用 sha1 或 md5");
  121. }
  122. algorithm = System.Security.Cryptography.MD5.Create();
  123. }
  124. return algorithm.ComputeHash(stream);
  125. }
  126. /// <summary>
  127. /// 计算哈希值
  128. /// </summary>
  129. /// <param name="stream">要计算哈希值的 Stream</param>
  130. /// <param name="algName">算法:sha1,md5</param>
  131. /// <returns>哈希值字节数组</returns>
  132. private static async Task<byte[]> HashDataAsync(this Stream stream, string algName)
  133. {
  134. System.Security.Cryptography.HashAlgorithm algorithm;
  135. if (algName == null)
  136. {
  137. throw new ArgumentNullException("algName 不能为 null");
  138. }
  139. if (string.Compare(algName, "sha1", true) == 0)
  140. {
  141. algorithm = System.Security.Cryptography.SHA1.Create();
  142. }
  143. else
  144. {
  145. if (string.Compare(algName, "md5", true) != 0)
  146. {
  147. throw new Exception("algName 只能使用 sha1 或 md5");
  148. }
  149. algorithm = System.Security.Cryptography.MD5.Create();
  150. }
  151. return await Task.Run(() => algorithm.ComputeHash(stream)).ConfigureAwait(false);
  152. }
  153. /// <summary>
  154. /// 字节数组转换为16进制表示的字符串
  155. /// </summary>
  156. private static string ByteArrayToHexString(byte[] buf) => BitConverter.ToString(buf).Replace("-", "");
  157. }
  158. }