public static List <FileInformation> FastFind(string path, string searchPattern, bool getFile, bool getDirectory, bool recurse, int?depth, bool parallel, bool suppressErrors, bool largeFetch, bool getHidden, bool getSystem, bool getReadOnly, bool getCompressed, bool getArchive, bool getReparsePoint, string filterMode) { object resultListLock = new object(); Win32Native.WIN32_FIND_DATAW lpFindFileData; Win32Native.FINDEX_ADDITIONAL_FLAGS additionalFlags = 0; if (largeFetch) { additionalFlags = Win32Native.FINDEX_ADDITIONAL_FLAGS.FindFirstExLargeFetch; } // add prefix to allow for maximum path of up to 32,767 characters string prefixedPath; if (path.StartsWith(@"\\")) { prefixedPath = path.Replace(@"\\", uncPrefix); } else { prefixedPath = normalPrefix + path; } var handle = Win32Native.FindFirstFileExW(prefixedPath + @"\*", Win32Native.FINDEX_INFO_LEVELS.FindExInfoBasic, out lpFindFileData, Win32Native.FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags); List <FileInformation> resultList = new List <FileInformation>(); List <FileInformation> subDirectoryList = new List <FileInformation>(); if (!handle.IsInvalid) { do { // skip "." and ".." if (lpFindFileData.cFileName != "." && lpFindFileData.cFileName != "..") { // if directory... if ((lpFindFileData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory) { // ...and if we are performing a recursive search... if (recurse) { // ... populate the subdirectory list string fullName = Path.Combine(path, lpFindFileData.cFileName); subDirectoryList.Add(new FileInformation { Path = fullName }); } } // skip folders if only the getFile parameter is used if (getFile && !getDirectory) { if ((lpFindFileData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory) { continue; } } // if file matches search pattern and attribute filter, add it to the result list if (MatchesFilter(lpFindFileData.dwFileAttributes, lpFindFileData.cFileName, searchPattern, getFile, getDirectory, getHidden, getSystem, getReadOnly, getCompressed, getArchive, getReparsePoint, filterMode)) { string fullName = Path.Combine(path, lpFindFileData.cFileName); long? thisFileSize = null; if ((lpFindFileData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory) { thisFileSize = (lpFindFileData.nFileSizeHigh * (2 ^ 32) + lpFindFileData.nFileSizeLow); } resultList.Add(new FileInformation { Name = lpFindFileData.cFileName, Path = Path.Combine(path, lpFindFileData.cFileName), Parent = path, Attributes = lpFindFileData.dwFileAttributes, FileSize = thisFileSize, CreationTime = lpFindFileData.ftCreationTime.ToDateTime(), LastAccessTime = lpFindFileData.ftLastAccessTime.ToDateTime(), LastWriteTime = lpFindFileData.ftLastWriteTime.ToDateTime() }); } } }while (Win32Native.FindNextFile(handle, out lpFindFileData)); // close the file handle handle.Dispose(); // handle recursive search if (recurse) { // handle depth of recursion if (depth > 0) { if (parallel) { subDirectoryList.AsParallel().ForAll(x => { List <FileInformation> resultSubDirectory = new List <FileInformation>(); resultSubDirectory = FastFind(x.Path, searchPattern, getFile, getDirectory, recurse, (depth - 1), false, suppressErrors, largeFetch, getHidden, getSystem, getReadOnly, getCompressed, getArchive, getReparsePoint, filterMode); lock (resultListLock) { resultList.AddRange(resultSubDirectory); } }); } else { foreach (FileInformation directory in subDirectoryList) { foreach (FileInformation result in FastFind(directory.Path, searchPattern, getFile, getDirectory, recurse, (depth - 1), false, suppressErrors, largeFetch, getHidden, getSystem, getReadOnly, getCompressed, getArchive, getReparsePoint, filterMode)) { resultList.Add(result); } } } } // if no depth are specified else if (depth == null) { if (parallel) { subDirectoryList.AsParallel().ForAll(x => { List <FileInformation> resultSubDirectory = new List <FileInformation>(); resultSubDirectory = FastFind(x.Path, searchPattern, getFile, getDirectory, recurse, null, false, suppressErrors, largeFetch, getHidden, getSystem, getReadOnly, getCompressed, getArchive, getReparsePoint, filterMode); lock (resultListLock) { resultList.AddRange(resultSubDirectory); } }); } else { foreach (FileInformation directory in subDirectoryList) { foreach (FileInformation result in FastFind(directory.Path, searchPattern, getFile, getDirectory, recurse, null, false, suppressErrors, largeFetch, getHidden, getSystem, getReadOnly, getCompressed, getArchive, getReparsePoint, filterMode)) { resultList.Add(result); } } } } } } // error handling else if (handle.IsInvalid && !suppressErrors) { int hr = Marshal.GetLastWin32Error(); if (hr != 2 && hr != 0x12) { //throw new Win32Exception(hr); Console.WriteLine("{0}: {1}", path, (new Win32Exception(hr)).Message); } } return(resultList); }
private static bool MatchesFilter(FileAttributes fileAttributes, string name, string searchPattern, bool aFile, bool aDirectory, bool aHidden, bool aSystem, bool aReadOnly, bool aCompressed, bool aArchive, bool aReparsePoint, string filterMode) { // first make sure that the name matches the search pattern if (Win32Native.PathMatchSpec(name, searchPattern)) { // then we build our filter attributes enumeration FileAttributes filterAttributes = new FileAttributes(); if (aDirectory) { filterAttributes |= FileAttributes.Directory; } if (aHidden) { filterAttributes |= FileAttributes.Hidden; } if (aSystem) { filterAttributes |= FileAttributes.System; } if (aReadOnly) { filterAttributes |= FileAttributes.ReadOnly; } if (aCompressed) { filterAttributes |= FileAttributes.Compressed; } if (aReparsePoint) { filterAttributes |= FileAttributes.ReparsePoint; } if (aArchive) { filterAttributes |= FileAttributes.Archive; } // based on the filtermode, we match the file with our filter attributes a bit differently switch (filterMode) { case "Include": if ((fileAttributes & filterAttributes) == filterAttributes) { return(true); } else { return(false); } case "Exclude": if ((fileAttributes & filterAttributes) != filterAttributes) { return(true); } else { return(false); } case "Strict": if (fileAttributes == filterAttributes) { return(true); } else { return(false); } } return(false); } else { return(false); } }
protected override bool ReleaseHandle() { return(Win32Native.FindClose(base.handle)); }