IoUtil.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.ComponentModel;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. namespace Bsm.Core
  6. {
  7. public static class IoUtil
  8. {
  9. public static long GetFileSize(string filename)
  10. {
  11. FindClose(FindFirstFile(filename, out var findData));
  12. return (((long)findData.nFileSizeHigh) << 32) | findData.nFileSizeLow;
  13. }
  14. public static bool GetFileInfo(string path, out WIN32_FIND_DATA data)
  15. {
  16. var hFind = FindFirstFileEx(path, FINDEX_INFO_LEVELS.FindExInfoBasic, out var file, 0, IntPtr.Zero, 0);
  17. if (hFind == new IntPtr(INVALID_HANDLE_VALUE))
  18. {
  19. var ex = new Win32Exception();
  20. data = new WIN32_FIND_DATA();
  21. return false;
  22. }
  23. data = file;
  24. FindClose(hFind);
  25. return true;
  26. }
  27. public static void LookupEntries(string dir, Action<WIN32_FIND_DATA> callback, string pattern = "*")
  28. {
  29. var hFind = FindFirstFileEx(Path.Combine(dir, pattern), FINDEX_INFO_LEVELS.FindExInfoBasic, out var file, 0, IntPtr.Zero, 0);
  30. if (hFind == new IntPtr(INVALID_HANDLE_VALUE))
  31. {
  32. var ex = new Win32Exception();
  33. return;
  34. }
  35. try
  36. {
  37. do
  38. {
  39. //check is . or ..
  40. if (file.cFileName == "." || file.cFileName == "..") continue;
  41. callback(file);
  42. } while (FindNextFile(hFind, out file));
  43. }
  44. finally
  45. {
  46. FindClose(hFind);
  47. }
  48. }
  49. public static void LookupFilesRecursively(string dir, Action<WIN32_FIND_DATA, string> callback, string pattern = "*")
  50. {
  51. LookupFilesInternal(dir, callback, pattern: pattern);
  52. }
  53. private static void LookupFilesInternal(string dir, Action<WIN32_FIND_DATA, string> callback, string folderName = "", string pattern = "*")
  54. {
  55. var hFind = FindFirstFileEx(Path.Combine(dir, pattern), FINDEX_INFO_LEVELS.FindExInfoBasic, out var file, 0, IntPtr.Zero, 0);
  56. if (hFind == new IntPtr(INVALID_HANDLE_VALUE))
  57. {
  58. var ex = new Win32Exception();
  59. return;
  60. }
  61. try
  62. {
  63. do
  64. {
  65. //check is . or ..
  66. if (file.cFileName == "." || file.cFileName == "..") continue;
  67. //check is dir re
  68. if (file.IsDirectory)
  69. {
  70. LookupFilesInternal(Path.Combine(dir, file.cFileName), callback, folderName + "/" + file.cFileName, pattern);
  71. continue;
  72. }
  73. callback(file, folderName);
  74. } while (FindNextFile(hFind, out file));
  75. }
  76. finally
  77. {
  78. FindClose(hFind);
  79. }
  80. }
  81. // ReSharper disable IdentifierTypo
  82. // ReSharper disable InconsistentNaming
  83. // ReSharper disable MemberCanBePrivate.Local
  84. // ReSharper disable FieldCanBeMadeReadOnly.Local
  85. [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
  86. private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
  87. [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  88. public static extern IntPtr FindFirstFileEx(
  89. string lpFileName,
  90. FINDEX_INFO_LEVELS fInfoLevelId,
  91. out WIN32_FIND_DATA lpFindFileData,
  92. FINDEX_SEARCH_OPS fSearchOp,
  93. IntPtr lpSearchFilter,
  94. int dwAdditionalFlags);
  95. [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
  96. private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
  97. [DllImport("kernel32.dll")]
  98. private static extern bool FindClose(IntPtr hFindFile);
  99. public const int INVALID_HANDLE_VALUE = -1;
  100. public const uint FILE_ATTRIBUTE_DIRECTORY = 16;
  101. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  102. public struct WIN32_FIND_DATA
  103. {
  104. public uint dwFileAttributes;
  105. public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
  106. public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
  107. public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
  108. public uint nFileSizeHigh;
  109. public uint nFileSizeLow;
  110. public uint dwReserved0;
  111. public uint dwReserved1;
  112. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
  113. public string cFileName;
  114. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
  115. public string cAlternateFileName;
  116. public bool IsDirectory => 0 != (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  117. public long FileSize => (((long)nFileSizeHigh) << 32) | nFileSizeLow;
  118. public DateTime CreationTime
  119. {
  120. get
  121. {
  122. var high = (ulong)ftCreationTime.dwHighDateTime;
  123. var low = (uint)ftCreationTime.dwLowDateTime;
  124. var fileTime = (long)((high << 32) + low);
  125. return DateTime.FromFileTimeUtc(fileTime);
  126. }
  127. }
  128. public DateTime LastWriteTime
  129. {
  130. get
  131. {
  132. var high = (ulong)ftLastWriteTime.dwHighDateTime;
  133. var low = (uint)ftLastWriteTime.dwLowDateTime;
  134. var fileTime = (long)((high << 32) + low);
  135. return DateTime.FromFileTimeUtc(fileTime);
  136. }
  137. }
  138. }
  139. public enum FINDEX_INFO_LEVELS
  140. {
  141. FindExInfoStandard = 0,
  142. FindExInfoBasic = 1
  143. }
  144. public enum FINDEX_SEARCH_OPS
  145. {
  146. FindExSearchNameMatch = 0,
  147. FindExSearchLimitToDirectories = 1,
  148. FindExSearchLimitToDevices = 2
  149. }
  150. // ReSharper restore FieldCanBeMadeReadOnly.Local
  151. // ReSharper restore MemberCanBePrivate.Local
  152. // ReSharper restore InconsistentNaming
  153. // ReSharper restore IdentifierTypo
  154. }
  155. }