2016-12-07 8 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,000 +에서 때로는 매일 매일 다를 수 있음)

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 (list에있는 fileName) {}}'로 변환 할 수 있습니다. 메소드의 아키텍처와 호출 방식을 변경해야하지만, 논리적으로 이중 foreach는 모두 수행하고 코드가 모두 인라인되면 'foreach'의 순서를 열거 할 수 있습니다. 한 번만. – Quantic

+0

답장을 보내 주셔서 감사합니다. 순서를 바꾸면 ForEach가 검색 할 때 어떤 "폴더 경로"가 전달 될지 알 수 없습니다. – Jayarikahs

답변

1

예제에서는 6 번 열거하지 않고 A 폴더를 세 번, 폴더 B을 두 번, 폴더 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,000 개 파일에 대해 어떻게 작동하는지 확인합니다. 모든 도움을 주셔서 다시 한 번 감사드립니다. – 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