You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

780 lines
29 KiB

3 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Internals;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Reflection;
  6. using System.Security.Permissions;
  7. namespace Apewer
  8. {
  9. /// <summary>存储实用工具。</summary>
  10. public static class StorageUtility
  11. {
  12. private static Exception Try(Action action)
  13. {
  14. try { action?.Invoke(); return null; }
  15. catch (Exception ex) { return ex; }
  16. }
  17. /// <summary>文件操作线程锁。</summary>
  18. public static object Locker = new object();
  19. #region NTFS 流
  20. /// <summary>获取标记的路径。</summary>
  21. public static string GetZoneIdentifier(string path) => NtfsUnlocker.GetZoneIdentifier(path);
  22. /// <summary>检查标记是否存在。</summary>
  23. public static bool ZoneIdentifierExists(string zoneIdentifier) => NtfsUnlocker.ZoneIdentifierExists(zoneIdentifier);
  24. /// <summary>删除标记。</summary>
  25. public static bool DeleteZoneIdentifier(string zoneIdentifier) => NtfsUnlocker.DeleteZoneIdentifier(zoneIdentifier);
  26. #endregion
  27. #region delete
  28. /// <summary>删除文件。</summary>
  29. public static Exception DeleteFile(string path, bool useTemp = false)
  30. {
  31. if (useTemp)
  32. {
  33. try
  34. {
  35. if (string.IsNullOrEmpty(path)) return new ArgumentException();
  36. if (!File.Exists(path)) return new FileNotFoundException();
  37. Try(() => new FileInfo(path).Attributes = FileAttributes.Normal);
  38. var temp = Environment.GetEnvironmentVariable("TEMP");
  39. var name = Path.GetFileName(path);
  40. var dest = null as string;
  41. while (dest == null || File.Exists(dest))
  42. {
  43. var guid = Guid.NewGuid().ToString("n").Substring(0, 8);
  44. dest = $"trash_{guid}_{name}";
  45. }
  46. File.Move(path, dest);
  47. File.Delete(dest);
  48. return null;
  49. }
  50. catch (Exception ex) { return ex; }
  51. }
  52. try
  53. {
  54. File.Delete(path);
  55. return null;
  56. }
  57. catch (Exception ex) { return ex; }
  58. }
  59. /// <summary>删除目录、子目录和子文件。</summary>
  60. public static Exception DeleteDirectory(string path, bool useTemp = false)
  61. {
  62. if (useTemp)
  63. {
  64. try
  65. {
  66. if (string.IsNullOrEmpty(path)) return new ArgumentException();
  67. if (!Directory.Exists(path)) return new DirectoryNotFoundException();
  68. var temp = Environment.GetEnvironmentVariable("TEMP");
  69. var name = Path.GetDirectoryName(path);
  70. var dest = null as string;
  71. while (dest == null || Directory.Exists(dest))
  72. {
  73. var guid = Guid.NewGuid().ToString("n").Substring(0, 8);
  74. dest = $"trash_{guid}_{name}";
  75. }
  76. Directory.Move(path, dest);
  77. Directory.Delete(dest, true);
  78. return null;
  79. }
  80. catch (Exception ex) { return ex; }
  81. }
  82. try
  83. {
  84. Directory.Delete(path, true);
  85. return null;
  86. }
  87. catch (Exception ex) { return ex; }
  88. }
  89. #endregion
  90. #region path
  91. /// <summary>无效的路径字符。</summary>
  92. public static char[] InvalidPathChars
  93. {
  94. // SMB 共享文件夹无效字符
  95. // ! " # % & ' ( ) * + , / : ; < = > ? @ [ ] \ ^ ` { } | ~
  96. get => new char[] {
  97. '\\', '/', '\'', '"', ':', '*', '?', '<', '>', '|',
  98. '\0', '\a', '\b', '\t', '\n', '\v', '\f', '\r',
  99. '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u000e', '\u000f',
  100. '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017',
  101. '\u0018', '\u0019', '\u001a', '\u001b', '\u001c', '\u001d', '\u001e', '\u001f'
  102. };
  103. }
  104. /// <summary>合并路径。</summary>
  105. public static string CombinePath(params string[] paths)
  106. {
  107. if (paths == null || paths.Length < 1) return "";
  108. try
  109. {
  110. #if NET20
  111. var result = paths[0];
  112. for (var i = 0; i < paths.Length; i++)
  113. {
  114. result = Path.Combine(result, paths[i]);
  115. }
  116. return result;
  117. #else
  118. return Path.Combine(paths);
  119. #endif
  120. }
  121. catch { return ""; }
  122. }
  123. /// <summary>获取文件或目录的存在状态。</summary>
  124. public static bool PathExists(string path)
  125. {
  126. if (string.IsNullOrEmpty(path)) return false;
  127. if (File.Exists(path)) return true;
  128. if (Directory.Exists(path)) return true;
  129. return false;
  130. }
  131. /// <summary>获取目录的存在状态。</summary>
  132. public static bool DirectoryExists(string path) => string.IsNullOrEmpty(path) ? false : Directory.Exists(path);
  133. /// <summary>获取文件的存在状态。</summary>
  134. public static bool FileExists(string path) => string.IsNullOrEmpty(path) ? false : File.Exists(path);
  135. /// <summary>获取文件或目录的上级目录完整路径,失败时返回 NULL 值。。</summary>
  136. public static string GetParentPath(string path)
  137. {
  138. try
  139. {
  140. if (File.Exists(path)) return Path.GetDirectoryName(path);
  141. if (Directory.Exists(path)) return Directory.GetParent(path).FullName;
  142. }
  143. catch { }
  144. return null;
  145. }
  146. /// <summary>修正文件名,去除不允许的字符。</summary>
  147. public static string FixFileName(string fileName)
  148. {
  149. var result = fileName;
  150. if (string.IsNullOrEmpty(result))
  151. {
  152. result = Constant.EmptyString;
  153. }
  154. else
  155. {
  156. var invalid = InvalidPathChars;
  157. foreach (var c in invalid) result = result.Replace(c.ToString(), "");
  158. }
  159. if (result.Length > 0) result = result.Trim();
  160. return result;
  161. }
  162. /// <summary>获取指定目录的子目录,可指定递归子目录。</summary>
  163. public static List<string> GetSubDirectories(string dirPath, bool recursive = false, bool recurPrecedence = true) => GetSubDirectories(dirPath, recursive ? -1 : 0, recurPrecedence);
  164. /// <summary>获取指定目录下子目录的路径。</summary>
  165. /// <param name="dirPath">顶级目录。</param>
  166. /// <param name="recurDepth">子目录递归深度,指定为 0 时不递归,指定为 -1 时无限递归。</param>
  167. /// <param name="recurPrecedence">优先排列递归项。</param>
  168. public static List<string> GetSubDirectories(string dirPath, int recurDepth, bool recurPrecedence = true)
  169. {
  170. var list = new List<string>();
  171. if (string.IsNullOrEmpty(dirPath)) return list;
  172. var directories = new string[0];
  173. try
  174. {
  175. directories = Directory.GetDirectories(dirPath);
  176. }
  177. catch { }
  178. foreach (var dir in directories)
  179. {
  180. var recurlist = new List<string>();
  181. if (recurDepth != 0)
  182. {
  183. var depth = (recurDepth > 0) ? recurDepth - 1 : recurDepth;
  184. var subrecur = GetSubDirectories(dir, depth, recurPrecedence);
  185. recurlist.AddRange(subrecur);
  186. }
  187. if (recurPrecedence)
  188. {
  189. list.AddRange(recurlist);
  190. list.Add(dir);
  191. }
  192. else
  193. {
  194. list.Add(dir);
  195. list.AddRange(recurlist);
  196. }
  197. }
  198. return list;
  199. }
  200. /// <summary>获取指定目录的子文件。</summary>
  201. /// <param name="dirPath">要查询的目录。</param>
  202. /// <param name="recursive">递归子目录。</param>
  203. /// <param name="recurPrecedence">优先排列递归项。</param>
  204. public static List<string> GetSubFiles(string dirPath, bool recursive = false, bool recurPrecedence = true) => GetSubFiles(dirPath, recursive ? -1 : 0, recurPrecedence);
  205. /// <summary>获取指定目录下子文件的路径。</summary>
  206. /// <param name="dirPath">要查询的目录。</param>
  207. /// <param name="recurDepth">子目录递归深度,指定为 0 时不递归,指定为 -1 时无限递归。</param>
  208. /// <param name="recurPrecedence">优先排列递归项。</param>
  209. public static List<string> GetSubFiles(string dirPath, int recurDepth, bool recurPrecedence = true)
  210. {
  211. var list = new List<string>();
  212. if (string.IsNullOrEmpty(dirPath)) return list;
  213. var dirs = new List<string>();
  214. if (recurDepth == 0)
  215. {
  216. dirs.Add(dirPath);
  217. }
  218. else
  219. {
  220. var recurdicrotylist = GetSubDirectories(dirPath, recurDepth, recurPrecedence);
  221. if (recurPrecedence)
  222. {
  223. dirs.AddRange(recurdicrotylist);
  224. dirs.Add(dirPath);
  225. }
  226. else
  227. {
  228. dirs.Add(dirPath);
  229. dirs.AddRange(recurdicrotylist);
  230. }
  231. }
  232. foreach (var d in dirs)
  233. {
  234. try
  235. {
  236. var files = System.IO.Directory.GetFiles(d);
  237. list.AddRange(files);
  238. }
  239. catch { }
  240. }
  241. return list;
  242. }
  243. #endregion
  244. #region directory
  245. /// <summary>确信指定存在指定目录。</summary>
  246. public static bool AssureDirectory(string path)
  247. {
  248. if (string.IsNullOrEmpty(path)) return false;
  249. try
  250. {
  251. if (File.Exists(path)) return false;
  252. if (Directory.Exists(path)) return true;
  253. var created = Directory.CreateDirectory(path);
  254. return created.Exists;
  255. }
  256. catch { }
  257. return false;
  258. }
  259. /// <summary>确信指定存在指定路径所在的上级目录。</summary>
  260. public static bool AssureParent(string path)
  261. {
  262. if (string.IsNullOrEmpty(path)) return false;
  263. var parent = Constant.EmptyString;
  264. try { parent = Directory.GetParent(path).FullName; } catch { }
  265. var result = AssureDirectory(parent);
  266. return result;
  267. }
  268. #endregion
  269. #region file
  270. /// <summary>打开文件,并获取文件流。若文件不存在,则先创建文件;若获取失败,则返回 NULL 值。可选文件的锁定状态。</summary>
  271. public static FileStream OpenFile(string path, bool share = true)
  272. {
  273. try
  274. {
  275. if (string.IsNullOrEmpty(path)) return null;
  276. if (DirectoryExists(path)) return null;
  277. if (AssureParent(path))
  278. {
  279. var m = FileMode.OpenOrCreate;
  280. var a = FileAccess.ReadWrite;
  281. var s = share ? FileShare.ReadWrite : FileShare.None;
  282. var stream = new FileStream(path, m, a, s);
  283. return stream;
  284. }
  285. }
  286. catch { }
  287. return null;
  288. }
  289. /// <summary>确保指定路径存在文件,若不存在则新建。</summary>
  290. /// <param name="path">文件路径。</param>
  291. public static bool AssureFile(string path)
  292. {
  293. if (string.IsNullOrEmpty(path)) return false;
  294. if (File.Exists(path)) return true;
  295. if (Directory.Exists(path)) return false;
  296. if (!AssureParent(path)) return false;
  297. try
  298. {
  299. File.Create(path).Dispose();
  300. return true;
  301. }
  302. catch
  303. {
  304. return false;
  305. }
  306. }
  307. /// <summary>创建一个空文件且不保留句柄。</summary>
  308. /// <param name="path">文件路径,若已存在则返回失败。</param>
  309. /// <param name="length">文件长度(字节数)。</param>
  310. /// <param name="replace">替换现有文件。</param>
  311. /// <returns>创建成功。</returns>
  312. public static bool CreateFile(string path, long length = 0, bool replace = false)
  313. {
  314. if (string.IsNullOrEmpty(path)) return false;
  315. if (!replace && File.Exists(path)) return false;
  316. if (!AssureParent(path)) return false;
  317. lock (Locker)
  318. {
  319. var file = null as FileStream;
  320. var success = false;
  321. try
  322. {
  323. var m = replace ? FileMode.Create : FileMode.OpenOrCreate;
  324. file = new FileStream(path, m, FileAccess.ReadWrite, FileShare.ReadWrite);
  325. if (length > 0) file.SetLength(length);
  326. success = true;
  327. }
  328. catch { }
  329. RuntimeUtility.Dispose(file);
  330. return success;
  331. }
  332. }
  333. /// <summary>复制文件。</summary>
  334. /// <param name="source">旧路径。</param>
  335. /// <param name="destination">新路径。</param>
  336. /// <param name="replace">新路径存在时,替换新文件。</param>
  337. public static bool CopyFile(string source, string destination, bool replace = true)
  338. {
  339. if (string.IsNullOrEmpty(source)) return false;
  340. if (string.IsNullOrEmpty(destination)) return false;
  341. lock (Locker)
  342. {
  343. if (!FileExists(source)) return false;
  344. try
  345. {
  346. File.Copy(source, destination, replace);
  347. return true;
  348. }
  349. catch { return false; }
  350. }
  351. }
  352. /// <summary>向文件追加数据。文件不存在时将创建。</summary>
  353. public static bool AppendFile(string path, params byte[] bytes)
  354. {
  355. if (bytes == null || bytes.Length < 1) return false;
  356. lock (Locker)
  357. {
  358. var assured = AssureParent(path);
  359. if (!assured) return false;
  360. using (var file = OpenFile(path, true))
  361. {
  362. if (file == null) return false;
  363. try
  364. {
  365. file.Position = file.Length;
  366. file.Write(bytes, 0, bytes.Length);
  367. file.Flush();
  368. return true;
  369. }
  370. catch { return false; }
  371. }
  372. }
  373. }
  374. /// <summary>将数据写入新文件,若文件已存在则覆盖。</summary>
  375. public static bool WriteFile(string path, params byte[] bytes) => WriteFile(path, false, bytes);
  376. /// <summary>将数据写入新文件,若文件已存在则覆盖。</summary>
  377. public static bool WriteFile(string path, bool bom, params byte[] bytes)
  378. {
  379. if (string.IsNullOrEmpty(path)) return false;
  380. if (bom)
  381. {
  382. lock (Locker)
  383. {
  384. if (bytes == null || bytes.Length < 1)
  385. {
  386. try
  387. {
  388. File.WriteAllBytes(path, TextUtility.Bom);
  389. return true;
  390. }
  391. catch
  392. {
  393. return false;
  394. }
  395. }
  396. else
  397. {
  398. var file = OpenFile(path, true);
  399. var success = false;
  400. try
  401. {
  402. var write1 = BytesUtility.Write(file, TextUtility.Bom);
  403. if (write1 == TextUtility.Bom.Length)
  404. {
  405. var write2 = BytesUtility.Write(file, bytes);
  406. if (bytes != null && bytes.LongLength > 0L)
  407. {
  408. }
  409. success = true;
  410. }
  411. }
  412. catch { }
  413. RuntimeUtility.Dispose(file);
  414. return success;
  415. }
  416. }
  417. }
  418. else
  419. {
  420. lock (Locker)
  421. {
  422. try
  423. {
  424. File.WriteAllBytes(path, bytes);
  425. return true;
  426. }
  427. catch
  428. {
  429. return false;
  430. }
  431. }
  432. }
  433. }
  434. /// <summary>读取文件,获取文件内容。当文件为 UTF-8 文本文件时,可去除 BOM 头。</summary>
  435. /// <remarks>注:<br />字节数组最大为 2GB;<br />此方法不抛出异常,读取失时返回空字节数组。</remarks>
  436. public static byte[] ReadFile(string path, bool wipeBom = false)
  437. {
  438. const int Buffer = 1048576;
  439. if (!FileExists(path)) return Constant.EmptyBytes;
  440. lock (Locker)
  441. {
  442. try
  443. {
  444. var result = new byte[0];
  445. using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
  446. {
  447. if (!stream.CanRead) return result;
  448. stream.Position = 0;
  449. var length = stream.Length;
  450. if (length < 1) return result;
  451. if (length > int.MaxValue) return result;
  452. var offset = 0L;
  453. if (wipeBom && length >= 3)
  454. {
  455. var head = new byte[3];
  456. stream.Read(head, 0, 3);
  457. if (TextUtility.ContainsBOM(head))
  458. {
  459. var capacity = length - 3;
  460. result = new byte[capacity];
  461. }
  462. else
  463. {
  464. result = new byte[length];
  465. result[0] = head[0];
  466. result[1] = head[1];
  467. result[2] = head[2];
  468. offset = 3;
  469. }
  470. }
  471. else
  472. {
  473. result = new byte[length];
  474. }
  475. var block = new byte[Buffer];
  476. while (true)
  477. {
  478. var read = stream.Read(block, 0, Buffer);
  479. if (read < 1) break;
  480. Array.Copy(block, 0, result, offset, read);
  481. offset += read;
  482. }
  483. }
  484. return result;
  485. }
  486. catch { }
  487. }
  488. return Constant.EmptyBytes;
  489. }
  490. /// <summary>获取指定文件的字节数,获取失败时返回 -1 值。</summary>
  491. public static long GetFileLength(string path)
  492. {
  493. try
  494. {
  495. var info = new FileInfo(path);
  496. return info.Length;
  497. }
  498. catch { }
  499. return -1;
  500. }
  501. #endregion
  502. /// <summary>获取文件的最后写入时间。</summary>
  503. public static DateTime GetFileLastWriteTime(string path, bool utc = false)
  504. {
  505. try
  506. {
  507. var info = new FileInfo(path);
  508. return utc ? info.LastWriteTimeUtc : info.LastWriteTime;
  509. }
  510. catch { }
  511. return new DateTime();
  512. }
  513. /// <summary>设置文件的最后写入时间。</summary>
  514. public static string SetFileLastWriteTime(string path, DateTime value)
  515. {
  516. try
  517. {
  518. var info = new FileInfo(path);
  519. info.LastWriteTime = value;
  520. return null;
  521. }
  522. catch (Exception ex)
  523. {
  524. return ex.Message;
  525. }
  526. }
  527. /// <summary>压缩文件到流。</summary>
  528. /// <param name="files">Key 为 ZIP 内的文件名,Value 为原始文件路径。</param>
  529. /// <param name="output">要输出的 ZIP 流。</param>
  530. public static Exception ToZip(Dictionary<string, string> files, Stream output)
  531. {
  532. if (files == null) return new ArgumentNullException(nameof(files));
  533. var streams = new List<Stream>();
  534. var ex = BytesUtility.ToZip(files.Keys, output, (name) =>
  535. {
  536. if (name.IsEmpty()) return null;
  537. var path = files[name];
  538. if (path.IsEmpty()) return null;
  539. if (!FileExists(path)) return null;
  540. var input = OpenFile(path);
  541. streams.Add(input);
  542. return input;
  543. }, (name) => GetFileLastWriteTime(files[name]), true);
  544. RuntimeUtility.Dispose(streams);
  545. return ex;
  546. }
  547. /// <summary>压缩文件到流。</summary>
  548. /// <param name="files">Key 为 ZIP 内的文件名,Value 为原始文件路径。</param>
  549. /// <param name="output">要输出的 ZIP 文件路径,已存在的文件将被删除。</param>
  550. public static Exception ToZip(Dictionary<string, string> files, string output)
  551. {
  552. if (output.IsEmpty()) return new ArgumentException(nameof(output));
  553. if (FileExists(output)) DeleteFile(output);
  554. if (FileExists(output)) return new IOException();
  555. var stream = OpenFile(output);
  556. if (stream == null) return new IOException();
  557. var ex = ToZip(files, stream);
  558. RuntimeUtility.Dispose(stream, true);
  559. return ex;
  560. }
  561. /// <summary>压缩文件到流。</summary>
  562. /// <param name="directory">原始文件目录。</param>
  563. /// <param name="output">要输出的 ZIP 流。</param>
  564. public static Exception ToZip(string directory, Stream output)
  565. {
  566. if (!DirectoryExists(directory)) return new DirectoryNotFoundException();
  567. var dict = new Dictionary<string, string>();
  568. foreach (var path in GetSubFiles(directory, true))
  569. {
  570. var name = path.Substring(directory.Length);
  571. if (name.StartsWith("\\")) name = name.Substring(1);
  572. if (name.StartsWith("/")) name = name.Substring(1);
  573. dict.Add(name, path);
  574. }
  575. return ToZip(dict, output);
  576. }
  577. /// <summary>压缩文件到流。</summary>
  578. /// <param name="directory">原始文件目录。</param>
  579. /// <param name="output">要输出的 ZIP 文件路径,已存在的旧文件将被删除。</param>
  580. public static Exception ToZip(string directory, string output)
  581. {
  582. if (output.IsEmpty()) return new ArgumentException(nameof(output));
  583. if (FileExists(output)) DeleteFile(output);
  584. if (FileExists(output)) return new IOException("无法删除现有文件。");
  585. var stream = OpenFile(output);
  586. if (stream == null) return new IOException("无法创建文件。");
  587. var ex = ToZip(directory, stream);
  588. RuntimeUtility.Dispose(stream, true);
  589. return ex;
  590. }
  591. /// <summary>解压 ZIP 文件到目标目录。已存在的旧文件将被删除。</summary>
  592. public static Exception FromZip(string zipPath, string outputDirectory = null)
  593. {
  594. if (!FileExists(zipPath)) return new FileNotFoundException("指定的 ZIP 文件路径无效。");
  595. var directory = outputDirectory;
  596. if (directory.IsEmpty())
  597. {
  598. if (zipPath.Lower().EndsWith(".zip"))
  599. {
  600. directory = zipPath.Substring(0, zipPath.Length - 4);
  601. //if (directory.EndsWith("/") || directory.EndsWith("\\"))
  602. //if (PathExists(directory)) directory = null;
  603. }
  604. else
  605. {
  606. directory = GetParentPath(zipPath);
  607. }
  608. }
  609. if (directory.IsEmpty()) return new ArgumentException("无法判断目录路径。");
  610. if (!AssureDirectory(directory)) return new DirectoryNotFoundException("无法创建目录。");
  611. var input = OpenFile(zipPath);
  612. if (input == null) return new IOException("无法打开 ZIP 文件。");
  613. var info = new Dictionary<string, DateTime>();
  614. var ex = BytesUtility.FromZip(input, (name, size, modifield) =>
  615. {
  616. var path = Path.Combine(directory, name);
  617. if (FileExists(path)) DeleteFile(path);
  618. if (DirectoryExists(path)) DeleteDirectory(path, true);
  619. if (PathExists(path)) throw new IOException("无法删除旧文件或旧目录。");
  620. var output = OpenFile(path);
  621. if (output == null) throw new IOException("无法创建文件 " + path + "。");
  622. if (info.ContainsKey(path))
  623. {
  624. RuntimeUtility.Dispose(output);
  625. return null;
  626. }
  627. info.Add(path, modifield);
  628. return output;
  629. }, (name, modified) =>
  630. {
  631. var path = Path.Combine(directory, name);
  632. var exists = AssureDirectory(path);
  633. if (!exists) throw new IOException("无法创建 ZIP 中对应的目录。");
  634. }, true);
  635. // 恢复文件的修改时间。
  636. foreach (var i in info) SetFileLastWriteTime(i.Key, i.Value);
  637. return ex;
  638. }
  639. ///// <summary>解压 ZIP 文件到字典。失败且不允许异常时返回 NULL 值。</summary>
  640. //public static Dictionary<string, byte[]> FromZip(string zipPath, bool allowException = false)
  641. //{
  642. // if (FileExists(zipPath))
  643. // {
  644. // var ex = new FileNotFoundException("文件不存在。");
  645. // if (allowException) throw ex;
  646. // return null;
  647. // }
  648. // var input = OpenFile(zipPath);
  649. // if (input == null)
  650. // {
  651. // var ex = new IOException("无法打开 ZIP 文件。");
  652. // if (allowException) throw ex;
  653. // return null;
  654. // }
  655. // return BinaryUtility.FromZip(input, ;
  656. //}
  657. /// <summary>获取指定程序集的资源。</summary>
  658. public static Stream GetResource(string name, Assembly assembly = null)
  659. {
  660. try
  661. {
  662. if (assembly == null) assembly = Assembly.GetExecutingAssembly();
  663. var stream = assembly.GetManifestResourceStream(name);
  664. return stream;
  665. }
  666. catch { }
  667. return null;
  668. }
  669. /// <summary>获取当前进程程序集的资源。读取失败时返回 NULL 值。</summary>
  670. public static byte[] ReadResource(string name, Assembly assembly = null)
  671. {
  672. var stream = GetResource(name, assembly);
  673. if (stream == null) return null;
  674. var bytes = BytesUtility.Read(stream, true);
  675. return bytes;
  676. }
  677. /// <summary>监视文件夹的变化。</summary>
  678. public static FileSystemWatcher NewFileSystemWatcher(string directory, FileSystemEventHandler action)
  679. {
  680. var watcher = new FileSystemWatcher();
  681. watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite | NotifyFilters.Size;
  682. watcher.IncludeSubdirectories = true;
  683. watcher.Path = directory;
  684. watcher.Created += (s, e) => action?.Invoke(watcher, e);
  685. watcher.Deleted += (s, e) => action?.Invoke(watcher, e);
  686. watcher.Changed += (s, e) => action?.Invoke(watcher, e);
  687. watcher.Renamed += (s, e) => action?.Invoke(watcher, e);
  688. watcher.EnableRaisingEvents = true;
  689. return watcher;
  690. }
  691. }
  692. }