[C#]使用FindFirstFile、FindNextFile API實做EnumerateFiles

[C#]使用FindFirstFile、FindNextFile API實做EnumerateFiles

.NET 4.0開始Directory類別新增了EnumerateFiles函式,該函式能提供較有效率的方式找尋檔案,不會等到整個搜尋動作完成才回傳。在.NET 4.0以前我們則可以用FindFirstFile、FindNextFile這幾個API來達到類似的效果。

 

實做起來就像下面這樣,有需要的自行取用:



		[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
		private static extern IntPtr FindFirstFile(string pFileName, ref  WIN32_FIND_DATA pFindFileData);

		[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
		private static extern bool FindNextFile(IntPtr hndFindFile, ref  WIN32_FIND_DATA lpFindFileData);  

		[DllImport( "kernel32.dll" , SetLastError =  true )]  
		private  static  extern  bool  FindClose(IntPtr hndFindFile);     

		[Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto), BestFitMapping(false)]
		internal struct WIN32_FIND_DATA
		{
			public FileAttributes dwFileAttributes;
			public uint ftCreationTime_dwLowDateTime;
			public uint ftCreationTime_dwHighDateTime;
			public uint ftLastAccessTime_dwLowDateTime;
			public uint ftLastAccessTime_dwHighDateTime;
			public uint ftLastWriteTime_dwLowDateTime;
			public uint ftLastWriteTime_dwHighDateTime;
			public uint nFileSizeHigh;
			public uint nFileSizeLow;
			public int dwReserved0;
			public int dwReserved1;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string cFileName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
			public string cAlternateFileName;
		}

		public IEnumerable<string> EnumerateFiles(string path, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
		{
			IntPtr hFind = INVALID_HANDLE_VALUE;
			WIN32_FIND_DATA FindFileData = default(WIN32_FIND_DATA);

			hFind = FindFirstFile(Path.Combine(path, searchPattern), ref  FindFileData);
			if (hFind != INVALID_HANDLE_VALUE)
			{
				do
				{
					if (FindFileData.cFileName.Equals(@".") || FindFileData.cFileName.Equals(@".."))
						continue;

					if (searchOption == SearchOption.AllDirectories && ((FindFileData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory))
					{
						foreach (var file in EnumerateFiles(Path.Combine(path, FindFileData.cFileName)))
							yield return file;
					}
					else
					{
						yield return Path.Combine(path, FindFileData.cFileName);
					}
				}
				while (FindNextFile(hFind, ref  FindFileData));
			}
			FindClose(hFind);
		}

 

Link