C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

フォルダー内のファイルリストを作成する方法

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■83842 / inTopicNo.1)  フォルダー内のファイルリストを作成する方法
  
□投稿者/ わんちゃん (1回)-(2017/04/13(Thu) 18:27:40)

分類:[.NET 全般] 

フォルダー内に含まれるファイル一覧を配列に格納するために、



        For Each fi As FileInfo In dirInfo.GetFiles()
            cnt += 1
            filepath(cnt) = fi.FullName

        Next fi

というコードを使っているのですが
ファイル数が10万個を超えると
dirInfo.GetFiles()
のところで
フリーズしたように時間がかかってしまいます。

せめてフォーム上に進行状況を表示できれば良いのですが
コマンドが一つであるため、それもできません。

フォームに進行状況を表示しながら
ファイルを検索するには昔ながらDir関数を使うしかないでしょうか?

あるいは、もっと高速に検索できる方法があれば教えてください。


引用返信 編集キー/
■83843 / inTopicNo.2)  Re[1]: フォルダー内のファイルリストを作成する方法
□投稿者/ PANG2 (173回)-(2017/04/13(Thu) 18:51:34)
Directory.EnumerateFilesメソッド
http://dobon.net/vb/dotnet/file/getfiles.html
引用返信 編集キー/
■83844 / inTopicNo.3)  Re[1]: フォルダー内のファイルリストを作成する方法
□投稿者/ 魔界の仮面弁士 (1258回)-(2017/04/13(Thu) 18:54:34)
No83842 (わんちゃん さん) に返信
> フォルダー内に含まれるファイル一覧を配列に格納するために、
> For Each fi As FileInfo In dirInfo.GetFiles()

GetFiles メソッドは、直下にあるファイルすべてを走査するまで
結果が返されないため、ファイル数が多いと列挙開始が遅くなります。

代わりに、.NET 4 以降で追加された EnumerateFiles メソッドを
使ってみてください。こちらは順次探索なのでファイル数が多くても大丈夫です。
引用返信 編集キー/
■83845 / inTopicNo.4)  Re[2]: フォルダー内のファイルリストを作成する方法
□投稿者/ わんちゃん (3回)-(2017/04/13(Thu) 19:14:59)
ありがとうございます。

調査不足でした
 
解決済み
引用返信 編集キー/
■83846 / inTopicNo.5)  Re[3]: フォルダー内のファイルリストを作成する方法
□投稿者/ わんちゃん (4回)-(2017/04/13(Thu) 20:25:00)
いま、試してみたのですが
ファイル数が多いと
For Each f As String In files

のところでフリーズしてしまいます。

一体なぜでしょうか?
 
引用返信 編集キー/
■83847 / inTopicNo.6)  Re[4]: フォルダー内のファイルリストを作成する方法
□投稿者/ 魔界の仮面弁士 (1259回)-(2017/04/14(Fri) 08:57:27)
No83846 (わんちゃん さん) に返信
> For Each f As String In files
> のところでフリーズしてしまいます。

変数 files は「String 型の一次元配列」でしょうか?
もしそうなら、フリーズしたときの files.Length の値を教えてください。
引用返信 編集キー/
■83848 / inTopicNo.7)  Re[5]: フォルダー内のファイルリストを作成する方法
□投稿者/ わんちゃん (5回)-(2017/04/14(Fri) 09:35:01)
試してみましたが

lengthはIEnumerable(Of String)のメンバーではありません

と表示されて値を取得できません
どうすれば良いですか?
 
引用返信 編集キー/
■83849 / inTopicNo.8)  Re[6]: フォルダー内のファイルリストを作成する方法
□投稿者/ shu (1006回)-(2017/04/14(Fri) 10:16:12)
No83848 (わんちゃん さん) に返信

フリーズという言葉は多分適切な表現ではないのではないでしょうか?
単純にファイルが多いのでループ回数が多いだけではないでしょうか?

> lengthはIEnumerable(Of String)のメンバーではありません

No83847 の魔界の仮面弁士様の回答にある質問に対しYesでないとlengthの
話は成り立たないのでそのようなエラーが発生します。

動作が遅くなっているコードは現在

      For Each fi As FileInfo In dirInfo.EnumerateFiles
            cnt += 1
            filepath(cnt) = fi.FullName

      Next fi

となっているのでしょうか?

        Dim filepath As New List(Of String)
        Dim dirInfo As New DirectoryInfo("・・・")

        Dim flEnum1 = dirInfo.EnumerateFiles
        Dim flEnum2 = flEnum1.GetEnumerator

        Do While flEnum2.MoveNext
            Dim fi = flEnum2.Current
            filepath.Add(fi.FullName)
        Loop

とした場合、どこが遅くなりますか?



引用返信 編集キー/
■83851 / inTopicNo.9)  Re[6]: フォルダー内のファイルリストを作成する方法
□投稿者/ 魔界の仮面弁士 (1261回)-(2017/04/14(Fri) 14:03:23)
No83848 (わんちゃん さん) に返信
>> 変数 files は「String 型の一次元配列」でしょうか?
>> もしそうなら、フリーズしたときの files.Length の値を教えてください。
> lengthはIEnumerable(Of String)のメンバーではありません
> と表示されて値を取得できません

もう一度、先の投稿を読み直してみてください。(^^;

私が Length (≠length) を試して欲しいと書いたのは、
  『変数 files が「String 型の一次元配列」』
の場合ですよ。


files.Legnth が上記のようなエラーを表示するのであれば、恐らくは
 Dim files As IEnumerable(Of String)
なデータ型なのだと思います。


DirectoryInfo クラスの GetFiles メソッドは『FileInfo()』を返します。
DirectoryInfo クラスの EnumerateFiles メソッドは『IEnumerable(Of FileInfo)』を返します。

Directory クラスの GetFiles メソッドは『String()』を返します。
Directory クラスの EnumerateFiles メソッドは『IEnumerable(Of String)』を返します。


最初に用いていた GetFiles メソッドは、結果を配列で返すため、
ファイルの列挙が完了するまで結果が返されません(これは先に述べましたね)。


一方 EnumerateFiles は即座に結果を返しますが、これは IEnumerable(Of ) です。
この場合、メソッドを呼び出しただけでは、実際には列挙が開始されません。
そのため、ファイルが多くてもメソッドの呼びだしは一瞬で完了します。

IEnumerable(Of ) を返すパターンの処理は、イメージとしては Dir 関数に近く、
結果を For Each で列挙するごとに、順次探索が行われるような仕組みになっています。
(Exit For すれば列挙が中止されます)


> ファイル数が多いと

10万個以上と仰っていましたが、具体的には幾つのファイルがあるのでしょうか。

また、そこにある全てのパスに対して、十分なアクセス権を有しているでしょうか。

Visual Studio からのデバッグ実行ではなく、Release ビルドでの EXE 実行でも
列挙が開始されないのでしょうか。(For Each の状況をログ出力するなどして確認)

---

同じ数のダミーファイルを用意してテストしてみれば再現できるのかもしれませんが、
こちらの環境ではフリーズする状況を確認できていません。

Dim files = Directory.EnumerateFiles("C:\", "*.*", SearchOption.AllDirectories)
For Each f As String In files
 Console.WriteLine(f)
Next

試しに上記のコードを実行してみましたが、アクセス権等での例外停止はあるものの、
列挙すら始まらない状況にはなりませんでした。
引用返信 編集キー/
■83852 / inTopicNo.10)  Re[7]: フォルダー内のファイルリストを作成する方法
□投稿者/ わんちゃん (6回)-(2017/04/15(Sat) 11:04:08)
ありがとうございます。

前回、試したコードは以下の通りです



        Dim files As IEnumerable(Of String) = Directory.EnumerateFiles("xxx", "*", SearchOption.AllDirectories)


        For Each f As String In files

            cnt += 1
            filepath(cnt) = f

        Next f



>魔界の仮面弁士さん

正確に4MBのファイルが10万個、一つのフォルダー内に入っています。

デバッグ実行ではなく、
Release ビルドでの EXE 実行でも試しましたが実行されませんでした。

あと、D:\で試すとすぐに列挙が開始されました。

もしかするとこのフォルダーがおかしいのかも知れません。
アクセス権限を見ましたが、
フルコントロールと特殊なアクセス許可以外には全て許可にチェックが入っています。


あと、フォルダーが入っているのはUSB3.0に接続された外付けHDDです。
速度は十分にありますが、外付けというのがもしかして原因ということはないですか?


>shuさん


        Dim filepath As New List(Of String)
        Dim dirInfo As New DirectoryInfo("・・・")

        Dim flEnum1 = dirInfo.EnumerateFiles
        Dim flEnum2 = flEnum1.GetEnumerator

        Do While flEnum2.MoveNext
            Dim fi = flEnum2.Current
            filepath.Add(fi.FullName)
        Loop


で試してみましたが、
        Do While flEnum2.MoveNext

のところで固まってしまいます。

ちなみにフリーズというのは30〜60秒くらいです。
完全にフリーズというわけではありません。

よろしくお願いいたします。




引用返信 編集キー/
■83858 / inTopicNo.11)  Re[8]: フォルダー内のファイルリストを作成する方法
□投稿者/ shu (1008回)-(2017/04/15(Sat) 13:09:11)
No83852 (わんちゃん さん) に返信
>
>
> で試してみましたが、
> Do While flEnum2.MoveNext
>
> のところで固まってしまいます。
>
> ちなみにフリーズというのは30〜60秒くらいです。
> 完全にフリーズというわけではありません。
>
そうすると1ファイル取得毎に30〜60秒かかっているということですね。
ドライバがおかしいとか、HDDのフォーマットによるものとか
USBケーブルが調子悪いとかでしょうか。
引用返信 編集キー/
■83860 / inTopicNo.12)  Re[9]: フォルダー内のファイルリストを作成する方法
□投稿者/ わんちゃん (7回)-(2017/04/15(Sat) 13:19:57)
一時間以上かかりましたが、
外付けHDDから内蔵HDDに全ファイルをコピーして試してみました
するとフリーズすることなく
実行できることが分かりました。

となると外付けHDDに問題があるようです
外付けHDD自体はケーブルやドライバに異常があるとは思えません

となると、
この関数が外付けHDDに対応していない
ということはありませんか?
 
引用返信 編集キー/
■83861 / inTopicNo.13)  Re[10]: フォルダー内のファイルリストを作成する方法
□投稿者/ わんちゃん (8回)-(2017/04/15(Sat) 13:58:47)
2017/04/15(Sat) 14:00:11 編集(投稿者)
2017/04/15(Sat) 13:59:34 編集(投稿者)

<pre><pre>

昔ながらの



        Dim buf As String
        buf = Dir(dirInfo.FullName & "\*.*")


        Do While buf <> ""
            filepath(cnt) = dirInfo.FullName & "\" & buf
            cnt = cnt + 1
            buf = Dir()

        Loop


という方法も試してみましたが
外付けHDDの場合には、
buf = Dir(dirInfo.FullName & "\*.*")のところで数十秒フリーズしてしまうことが分かりました。

あと、内蔵HDDであっても、


上記のDir関数の方法と


        Dim files As IEnumerable(Of String) = Directory.EnumerateFiles(dirInfo.FullName, "*", SearchOption.AllDirectories)
の方法だとわずかですがフリーズしてしまいます。



        Dim filepath As New List(Of String)
        Dim dirInfo As New DirectoryInfo(dirInfo0.FullName)

        Dim flEnum1 = dirInfo.EnumerateFiles
        Dim flEnum2 = flEnum1.GetEnumerator

        Dim cnt = 0
        Do While flEnum2.MoveNext

            cnt += 1
            Dim fi = flEnum2.Current
            filepath.Add(fi.FullName)
        Loop

の方法だとフリーズしないことが分かりました。

外付けHDDだと何が違うのでしょうか?
ちなみに7200rpmで1TBの2.5inch HDDです。




</pre></pre>

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ