2015/04/28(Tue) 16:25:05 編集(投稿者) 2015/04/28(Tue) 16:24:49 編集(投稿者) こんにちは。 指定されたフォルダ内の(サブフォルダ内も含む)ファイル総数を取得しようとしていまして、 BackgroundWorkerのDoWork内で、 int total = Directory.GetFiles(FolderName, "*", SearchOption.AllDirectories).Length; を実行しています。 コンピュータ起動後最初にこの場所を通るときに約40秒くらい掛かってしまいます。 次に通るときには1秒くらいで終わります。(キャッシュが効いている?) テストで使用しているデータはサブフォルダが約4000件、ファイル数が約10000件です。 OSは7(32・64ビット)、8.1(64ビット)とも同じ状態です。 実環境ではファイル数は増えます。 private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { int total = Directory.GetFiles(FolderName, "*", SearchOption.AllDirectories).Length; float f = total / 100; int count = 0; { 処理。。。 _backgroundWorker.ReportProgress((++count) / f); } } 処理に時間が掛かるためにプログレスバーで進行状況が分かるようにしようとしています。 このファイル総数を取得するのを早くする方法はありますでしょうか? よろしくお願いいたします。 【追記】 ファイル数を約1万件と書いていましたが、約10万件の間違いです。 私のミスです。申し訳ございませんでした。
■No32917に返信(レインさんの記事) > ■No32915に返信(shuさんの記事) > > お返事遅くなりましてすいません。 > >>ファイル総数ではなくサブディレクトリの数に対する進捗にするとか。 > > int total = Directory.GetDirectories(FolderName, "*", SearchOption.AllDirectories).Length; > > を試してみたのですが、GetFilesの時と同じく時間が掛かってしまいました。 > > 魔界の仮面弁士さんが書かれているようにSearchOption.AllDirectoriesは、 > この用途ではよくないのですかね? > 内容が分かりにくかったようですね。直下のフォルダー数という意味でサブディレクトリと書きました。つまりそのオプションはいりません。 直下のフォルダを取得して各フォルダに対し今の処理を行うようにしてそのフォルダ配下がすべて完了したらカウント1アップのようなイメージです。 4000フォルダ情報を読むのに時間がかかるようなら総数に対する進捗はあきらめた方がよいと思います。EnumerateDirectories, EnumerateFilesにより順次処理を行うようにすると一括で情報取得をしない分待ち時間を分散出来ると思います。
■No32925に返信(魔界の仮面弁士さんの記事) > あとは、FINDEX_INFO_LEVELS.FindExInfoBasic 指定の FindFirstFileEx とか。 APIのFindFirstFileExでテストしてみたのですが、大体35秒くらいでした。 public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; //ディレクトリ public enum FINDEX_INFO_LEVELS { FindExInfoStandard = 0, FindExInfoBasic = 1 } public enum FINDEX_SEARCH_OPS { FindExSearchNameMatch = 0, FindExSearchLimitToDirectories = 1, FindExSearchLimitToDevices = 2 } public struct WIN32_FIND_DATA { public uint dwFileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } [DllImport("kernel32.dll")] public static extern IntPtr FindFirstFileEx( string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, out WIN32_FIND_DATA lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags); [DllImport("kernel32.dll")] public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll")] public static extern bool FindClose(IntPtr hFindFile); private void FindFile(string lpFilename) { WIN32_FIND_DATA findData; IntPtr hFile = FindFirstFileEx( lpFilename, FINDEX_INFO_LEVELS.FindExInfoBasic, out findData, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0); if(hFile.ToInt32() != -1) { do { if((findData.dwFileAttributes) != FILE_ATTRIBUTE_DIRECTORY) ++FileCount; else { if(findData.cFileName == "." || findData.cFileName == "..") continue; else { FindFile(Path.Combine(Path.GetDirectoryName(lpFilename), findData.cFileName, @"*")); } } } while(FindNextFile(hFile, out findData)); FindClose(hFile); } } private int FileCount = 0; private string SrcFolderName = @"c:\hoge\"; private void startButton_Click(object sender, RoutedEventArgs e) { FileCount = 0; FindFile(Path.Combine(SrcFolderName, @"*")); } ファイル総数を求めて進捗状況を表示するというのは、なかなか難しそうですね。 別のアプローチを考えてみたいと思います。