C# get file names and last write times for large directories
Using C# (.NET 2.0), what is the best way to retrieve a file listing in a network directory, with preference to either sort by last write time, or to exclude the return based on last write time?
I'm currently bringing back a listing using the GetFiles method of a DirectoryInfo instance. The directories I encounter can contain over 6,000 files and just to get an a开发者_开发技巧rray of FileInfo back takes almost 25 seconds.
WMI will not work and I cannot see anything else that is .NET-centric that will help in this situation. Am I missing something? Is there a better solution than to use GetFiles?
Thank you.
Update
I just noticed this old answer, for .net 4.0 and later there is a System.IO.EnumerateFiles
method that does this for you, for everything pre .net 4.0, read on.
.Net 3.5 & Earlier
I'm with Stefan, I encountered this exact problem, and rolled my own enumerator to iterate over folders with +100k files.
This class wraps all the API specific stuff you'll need to use FindFirstFile and FindNextFile.
Hope this helps,
internal class APIWrapper
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class FILETIME
{
public int Low;
public int High;
public Int64 ToInt64()
{
Int64 h = High;
h = h << 32;
return h + Low;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class FindData
{
public int fileAttributes;
public FILETIME CreationTime;
public FILETIME LastAccessTime;
public FILETIME LastWriteTime;
public int FileSizeHigh;
public int FileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public String fileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public String alternateFileName;
}
internal sealed class SafeFindHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
/// <summary>
/// Constructor
/// </summary>
public SafeFindHandle()
: base(true)
{
}
/// <summary>
/// Release the find handle
/// </summary>
/// <returns>true if the handle was released</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected override bool ReleaseHandle()
{
return SafeNativeMethods.FindClose(handle);
}
}
internal enum SearchOptions
{
NameMatch,
LimitToDirectories,
LimitToDevices
}
[SecurityPermissionAttribute(SecurityAction.Assert, UnmanagedCode = true)]
internal static class SafeNativeMethods
{
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern SafeFindHandle FindFirstFile(String fileName, [In, Out] FindData findFileData);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern SafeFindHandle FindFirstFileEx(
String fileName, //__in LPCTSTR lpFileName,
[In] int infoLevel, //__in FINDEX_INFO_LEVELS fInfoLevelId,
[In, Out] FindData findFileData, //__out LPVOID lpFindFileData,
[In, Out] SearchOptions SerchOps, //__in FINDEX_SEARCH_OPS fSearchOp,
[In] int SearchFilter, //__reserved LPVOID lpSearchFilter,
[In] int AdditionalFlags); //__in DWORD dwAdditionalFlags
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData);
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindClose(IntPtr hFindFile);
}
}
Not the collation of the FileInfo instances is the problem, but the API call that is performed when accessing the last write time.
To get a significantly faster response, you have to call the Win32 API functions FindFirstFile and FindNextFile yourself.
精彩评论