適切なベンチマークを実行するために正しい作成日で十分な数のファイルを作成する気がしなかったので、開始時刻と終了時刻を取り、一致するファイルの名前を示す、より一般的なバージョンを作成しました。昨日作成されたファイルの特定の部分文字列を与えるようにすることは、当然のことです。
私が思いついた最も速いシングルスレッドの純粋な.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 ナノ秒か何かのように削り取る必要があります (それを行う重大な理由ではありません)。 、しかし、上記は基本的な考え方を示しています。