長い間、NTFSチューニングの一つに「短いファイル名を生成させない」という技がありました。Windows Server 2008 R2のベストプラクティスアナライザーでも遅いディスクに対してはこのアドバイスが下されます。
NTFS Performance with Numerous Long Filenames
とはいっても、短いファイル名の生成をやめると、どうしても互換性の問題が発生します。短いファイル名を意図的に使っている場合もあります。空白ファイル名使うときめんどくさいですしね…。じゃあ、OSのほうでなんとかすればいいじゃないってことで、遅まきながらWindows 7でフラグが追加されることになりました。FindExInfoBasicを指定すれば、短いファイル名をWIN32_FIND_DATA構造体に格納せず、少し早くなると書かれています。個人的にはVistaか、XPで追加してくれてもよかったと思わないでもないです…。
FindFirstFileEx function (Windows)
FINDEX_INFO_LEVELS enumeration (Windows)
#define WINVER 0x601 #include <windows.h> void FindNextTest(HANDLE hFile) { WIN32_FIND_DATA FindFileData; BOOL fRet; do { fRet = FindNextFile(hFile, &FindFileData); }while(fRet); } /* Windows Vistaまで */ void FindFirstTest1(LPCTSTR lpszName) { WIN32_FIND_DATA FindFileData; HANDLE hFile = FindFirstFileEx(lpszName, FindExInfoStandard , &FindFileData, FindExSearchNameMatch, NULL, 0); if(hFile != INVALID_HANDLE_VALUE) { FindNextTest(hFile); FindClose(hFile); } } /* Windows 7の拡張を使ったとき */ void FindFirstTest2(LPCTSTR lpszName) { WIN32_FIND_DATA FindFileData; HANDLE hFile = FindFirstFileEx(lpszName, FindExInfoBasic, &FindFileData, FindExSearchNameMatch, NULL, 0); if(hFile != INVALID_HANDLE_VALUE) { FindNextTest(hFile); FindClose(hFile); } }
Windows Server 2008 R2(2010/9/18時点のパッチ適用済み)において、このフラグ指定して11万弱のファイルをすべて列挙させると、FindFirstTest2()では手元の環境で81%くらいの時間になりました。あ、キャッシュなどに入らないように、実験ごとにOSを再起動しています。入っていると、1秒とか3秒で終わります。
Windows 7以降のOSで1フォルダ内に大量のファイルがあるならFindFirstFile()ではなく、FindFirstFileEx()でこのフラグ使いたいですね。
といっても、ふつうは.NET 4で強化されたDirectoryInfo.EnumerateFiles Method (String, SearchOption) (System.IO)あたりを使っていたほうが幸せだと思います…。