我不想用正确的创建日期创建足够的文件来做一个体面的基准,所以我做了一个更通用的版本,它需要一个开始和结束时间,并给出匹配的文件的名称。让它给出一个特定的昨天创建的文件的子字符串自然就是如此。
我想出了最快的单线程纯.NET的回答是:
private static IEnumerable<string> FilesWithinDates(string directory, DateTime minCreated, DateTime maxCreated)
{
foreach(FileInfo fi in new DirectoryInfo(directory).GetFiles())
if(fi.CreationTime >= minCreated && fi.CreationTime <= maxCreated)
yield return fi.Name;
}
我本来期望EnumerateFiles()
要稍微快一点,但事实证明,速度稍慢(可能会怎么做,如果你最好通过网络,但我没有测试)。
有一个轻微的增益:
private static ParallelQuery<string> FilesWithinDates(string directory, DateTime minCreated, DateTime maxCreated)
{
return new DirectoryInfo(directory).GetFiles().AsParallel()
.Where(fi => fi.CreationTime >= minCreated && fi.CreationTime <= maxCreated)
.Select(fi => fi.Name);
}
但不是很多,因为它不利于实际调用GetFiles()
。如果你没有使用内核,或者GetFiles()
没有足够大的结果,那么它会让事情变得更糟(AsParallel()
的开销大于并行过滤的好处)。另一方面,如果您也可以并行处理下一步的处理过程,那么总体应用程序速度可能会提高。
对EnumerateFiles()
这样做似乎没有意义,因为它似乎并不是很好并行,因为它基于我将要使用的相同方法,而且本质上是串行的 - 需要以前的结果来生成下一个。
我得到的最快的是:
public const int MAX_PATH = 260;
public const int MAX_ALTERNATE = 14;
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
public static implicit operator long(FILETIME ft)
{
return (((long)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
}
};
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)]
public string cAlternate;
}
[DllImport("kernel32", CharSet=CharSet.Unicode)]
public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", CharSet=CharSet.Unicode)]
public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll")]
public static extern bool FindClose(IntPtr hFindFile);
private static IEnumerable<string> FilesWithinDates(string directory, DateTime minCreated, DateTime maxCreated)
{
long startFrom = minCreated.ToFileTimeUtc();
long endAt = maxCreated.ToFileTimeUtc();
WIN32_FIND_DATA findData;
IntPtr findHandle = FindFirstFile(@"\\?\" + directory + @"\*", out findData);
if(findHandle != new IntPtr(-1))
{
do
{
if(
(findData.dwFileAttributes & FileAttributes.Directory) == 0
&&
findData.ftCreationTime >= startFrom
&&
findData.ftCreationTime <= endAt
)
{
yield return findData.cFileName;
}
}
while(FindNextFile(findHandle, out findData));
FindClose(findHandle);
}
}
它冒险不具有FindClose()
由IDisposable
答应了,并IEnumerator<string>
手卷实施不仅应该作出这样的容易做的(严重的理由这样做),但也希望像3纳秒或其他东西(不是一个严重的原因),但上面显示的基本思路。
你可以尝试使用LINQ。 – Bernard 2012-08-13 19:56:44