2016-12-07 3 views
0

私はVB.NETでこれを書いていましたが、私はC#でも快適です。私は、Windowsファイルシステム上で見つけたいファイルのリストを持っています。ファイル名に基づいて、別のディレクトリを調べる必要があります。私が持っているファイルのリストは、(動作する)プログラムの先頭にコンパイルし、ソートされていないDataTableに格納されているリストです。ここに私のアプローチがあります。ファイル番号の数を減らすことはできますか?

ファイルのDataTableの一覧ファイル名に基づいに見て

- a_111.txt 
- a_222.txt 
- b_333.txt 
- a_444.txt 
- c_555.txt 
- b_666.txt 

ディレクトリ(これは1,000s +で時々、日々異なります)

C:\a\ -- for files begin with a (variable name is A_folder) 
C:\b\ -- for files begin with b (variable name is B_folder) 
C:\c\ -- for files begin with c (variable name is C_folder) 

コード:

If DataTableofFiles IsNot Nothing AndAlso DataTableofFiles.Rows.Count > 0 Then 
    For Each row as DataRow In DataTableofFiles.Rows 
    If row("FILENAME").ToString.StartsWith("a") Then 
     Dim a_WriteResultstoA as String = "a.csv" 
     functionfindfiles(A_folder, row("FILENAME").ToString, a_WriteResultstoA) 
    ElseIf row("FILENAME").ToString.StartsWith("b") Then 
     Dim b_WriteResultstoB as String = "b.csv" 
     functionfindfiles(B_folder, row("FILENAME").ToString, b_WriteResultstoB) 
    ElseIf row("FILENAME").ToString.StartsWith("C") Then 
     Dim c_WriteResultstoC as String = "c.csv" 
     functionfindfiles(C_folder, row("FILENAME").ToString, c_WriteResultstoC) 
    End If 
    Next 
End If 

Private Sub functionfindfiles(sourcefolder As String, filename as String, writetofile As String) 
     Try 
      For Each f As String In Directory.EnumerateFiles(sourcefolder, "*.*", SearchOption.AllDirectories) '<-- file enumeration 
        If Path.GetFileName(f).Equals(filename, StringComparison.OrdinalIgnoreCase) Then 
         Using fs As New FileStream(writetofile, FileMode.Append, FileAccess.Write, FileShare.Write) 
          Using sw As StreamWriter = New StreamWriter(fs) 
           If Not New FileInfo(writetofile).Length > 0 Then 
            For i As Integer = 0 To DataTableofFiles.Columns.Count - 1 Step 1 
             sw.Write(DataTableofFiles.Columns(i).ToString) 

             If i < DataTableofFiles.Columns.Count - 1 Then 
              sw.Write(",") 
             End If 
            Next 

            sw.WriteLine() 
           End If 

           For Each row As DataRow In DataTableofFiles.Rows 
            If row("FILENAME").ToString = filename Then 
             For i As Integer = 0 To DataTableofFiles.Columns.Count - 1 Step 1 
              If Not Convert.IsDBNull(row(i)) Then 
               sw.Write(row(i).ToString.Replace(vbLf, "").Replace(",", ";")) 
              End If 

              If i < DataTableofFiles.Columns.Count - 1 Then 
               sw.Write(",") 
              End If 
             Next 

             sw.WriteLine() 
            End If 
           Next 
          End Using 
         End Using 
        Else 
         'write results that are not found here to a file 
        End If 
      Next 
     Catch ex As Exception 
    MessageBox.Show(ex.Message) 
     End Try 
End Sub 

この場合、ファイルシステムの列挙は6回発生します。ディレクトリにたくさんのファイルがあると、実行に本当に時間がかかることがあります。ファイル列挙の量を減らす良い方法がありますか?または、コード内の他の領域を改善して、必要以上に実行される追加の操作を減らすことができますか?アドバイスをいただければ幸いです。ありがとう!

+0

あなたのforeach'sを逆転させます。 {foreach(file in EnumerateFiles){}} 'を実行しますが、foreach(enumerateFiles内のファイル){foreach(リスト内のファイル名){}}'にそれらを逆順にすることができます。あなたのメソッドが何をするのか、どのように呼び出すのかのアーキテクチャを変更する必要がありますが、論理的には二重foreachがすべてです。コードがすべてインライン展開されている場合は、foreachの順序を自明に逆転できます1回だけ。 – Quantic

+0

返事をありがとう。注文を元に戻すと、ForEachが検索するためにどのような「フォルダパス」が渡されるのか分かりません。 – Jayarikahs

答えて

1

例で6回列挙されていません。フォルダAを3回、フォルダBを2回、フォルダCを1回列挙しています。これらの追加の列挙を減らすために、データテーブルを前処理して各フォルダのファイル名のリストを作成し、単一のファイル名ではなくファイル名のリストで作業するようにメソッドを変更することができます。私はVBで書かないので、ここではC#コードでマッシュアップする答えです(申し訳ありませんが、私は自分の考えをコメントに収めることができませんでした。すべて私はあなたの方法にした

注意foreach (var filename in listOfFileNames)に追加して、代わりにちょうどstring filenameList<string> listOfFileNamesを受け入れるように署名を変更し、呼び出し側は現在のリストを構築し、フォルダごとに一度メソッドを呼び出す前に、完全データテーブルforeachを終了します。

If DataTableofFiles IsNot Nothing AndAlso DataTableofFiles.Rows.Count > 0 Then 

    List<string> allAFileNames = new List<string>(); 
    List<string> allBFileNames = new List<string>(); 
    List<string> allCFileNames = new List<string>(); 

    For Each row as DataRow In DataTableofFiles.Rows 
    If row("FILENAME").ToString.StartsWith("a") Then 
     Dim a_WriteResultstoA as String = "a.csv" 

     allAFileNames.Add(row("FILENAME")); 

    ElseIf row("FILENAME").ToString.StartsWith("b") Then 
     Dim b_WriteResultstoB as String = "b.csv" 

     allBFileNames.Add(row("FILENAME")); 

    ElseIf row("FILENAME").ToString.StartsWith("C") Then 
     Dim c_WriteResultstoC as String = "c.csv" 

     allCFileNames.Add(row("FILENAME")); 

    End If 
    Next 

    if (allAFileNames.Count > 0) 
    { 
     functionfindfiles(A_folder, allAFileNames, a_WriteResultstoA); 
    } 

    if (allBFileNames.Count > 0) 
    { 
     functionfindfiles(B_folder, allBFileNames, b_WriteResultstoB) 
    } 

    if (allAFileNames.Count > 0) 
    { 
     functionfindfiles(C_folder, allCFileNames, c_WriteResultstoC) 
    } 

End If 

Private Sub functionfindfiles(sourcefolder As String, List<string> listOfFileNames, writetofile As String) 
     Try 
      For Each f As String In Directory.EnumerateFiles(sourcefolder, "*.*", SearchOption.AllDirectories) '<-- file enumeration 

        foreach (var filename in listOfFileNames) 
        { 

        If Path.GetFileName(f).Equals(filename, StringComparison.OrdinalIgnoreCase) Then 
         Using fs As New FileStream(writetofile, FileMode.Append, FileAccess.Write, FileShare.Write) 
          Using sw As StreamWriter = New StreamWriter(fs) 
           If Not New FileInfo(writetofile).Length > 0 Then 
            For i As Integer = 0 To DataTableofFiles.Columns.Count - 1 Step 1 
             sw.Write(DataTableofFiles.Columns(i).ToString) 

             If i < DataTableofFiles.Columns.Count - 1 Then 
              sw.Write(",") 
             End If 
            Next 

            sw.WriteLine() 
           End If 

           For Each row As DataRow In DataTableofFiles.Rows 
            If row("FILENAME").ToString = filename Then 
             For i As Integer = 0 To DataTableofFiles.Columns.Count - 1 Step 1 
              If Not Convert.IsDBNull(row(i)) Then 
               sw.Write(row(i).ToString.Replace(vbLf, "").Replace(",", ";")) 
              End If 

              If i < DataTableofFiles.Columns.Count - 1 Then 
               sw.Write(",") 
              End If 
             Next 

             sw.WriteLine() 
            End If 
           Next 
          End Using 
         End Using 
        Else 
         'write results that are not found here to a file 
        End If 
        } 
      Next 
     Catch ex As Exception 
    MessageBox.Show(ex.Message) 
     End Try 
End Sub 
+0

あなたは今何を意味するのか分かります。最初にファイル名に基づいてリストをコンパイルしてから、それを1回で渡す方が合理的です。オプションで、特定のフォルダ内の特定のファイルを探したいので、FileInfo(ファイル名).Existsを使用するように書き直しました。私はあなたのコードをテストし、両方のオプションが1,000sのファイルに対してどのように機能するかを見ていきます。あなたのご親切に感謝します。 – Jayarikahs

+0

'FileInfo'を再利用しないのであれば、ファイルの' FileInfo'ビュー全体を構築する必要がないので、単に 'File.Exists()'を実行するほうがパフォーマンスが良いかもしれません。また、私はデータテーブルについてはあまりよく分かりませんが、 'row(" FILENAME ")が実際のルックアップを行い、行が変更されていないことが分かっている場合は、値を一度保存​​して、 : 'string thisFilename = row(" FILENAME ")'。つまり、 'row(" FILENAME ")'は毎回実行するのに2秒かかるかもしれませんが、格納された変数を呼び出すことは基本的に自由です。 – Quantic

+0

FileInfo()。ExistsとFile.Exists()の両方をテストしたところ、結果は非常に似ています。時にはFileInfoの方が速く、それ以外はFileが高速でしたが、試行ごとに1秒しかかかりませんでした。私は1,000回の記録を取ったり記録したりしてテストしました。おそらく、ボリュームがはるかに大きかった場合、結果が異なる可能性があります。あなたのご親切に感謝します! – Jayarikahs

関連する問題