2015-01-16 5 views
1

전체 디렉터리에서 지정된 이름의 파일을 검색하는 재귀 검색이 있습니다. 꽤 많은 시간이 필요하며 적어도 진행 상황을 보여주는 진행 표시 줄을 보여주고 싶습니다. 진행률이 파일 또는 디렉토리의 수 또는 실제 크기로 측정되는 경우 상관 없습니다.재귀 검색에서 진행률 측정

private void searchFolder(PortableDeviceFolder parent, ref List<PortableDeviceFolder> result, string filename) 
{ 
    foreach (var item in parent.Files) 
    { 

     if (item is PortableDeviceFolder) 
     { 
      searchFolder((PortableDeviceFolder)item, ref result, filenames); 
     } 
     else if ((String.Compare(item.Name, filename)==0)) 
     { 
      result.Add(parent); 
      Console.WriteLine("Found file in: " + parent.Name); 
     }  
    } 
} 

내가 진행 상황을 얻는 방법을 알아낼 수 없습니다 : (재귀 코드)에 따라

검색을 수행합니다. 나는 각 파일과 폴더에 대해 같은 비율을 측정하는 쉬운 알고리즘을 생각하고 있었다.

  • 문서 (10 %)
    • privat의 (10 %/3)
    • 일 (10 %/3)
      • 프로젝트 1 (10 %/3/2)
      • 프로젝트 2 (10 %/3/2)
    • familly (10 %/3)
  • ,536,
  • ...

등등.

불행히도 재귀 적 검색에서 이것을 구현할 수 없었습니다. 아무도 나에게 모범이 될 시간이 없습니까? 미리 감사드립니다.

+0

필자는 재귀 깊이를 알려주는 새로운 'int'매개 변수를 메서드 시그니처에 추가하여 각 레벨 전체에서 차지하는 비율을 알 수 있다고 생각합니다. – adv12

+2

@ adv12 그러나 재귀 깊이가 충분하지 않다는 것을 알고, 정확한 분수를 얻으려면 각 디렉토리에 몇 개의 파일이나 폴더가 있는지 알아야합니다. – j0h4nn3s

+0

동의. 둘 다 필요합니다. – adv12

답변

1

Commenter TaW의 제안에 따라 진행 과정의 기초로 사용할 디렉토리를 계산할 수 있다는 것이 좋습니다. 그러나 제안 자체가 아니라 코드가 구현 된 것처럼 보이는 작은 문제가 있습니다.

귀하의 질문에 무엇이 PortableDeviceFolder인지 분명하지 않습니다. 그러나 파일과 폴더의 차이점을 추상화하여 모두 Files 속성에서 반환합니다. 처리에 가장 시간이 많이 걸리는 부분은 특정 디렉토리의 파일 이름을 실제로 검색 할 가능성이 높기 때문에 PortableDeviceFolder 메커니즘 만 주어진 디렉토리의 디렉토리를 반환해야하는 경우 Files 속성을 사용해야합니다. 카운트를 생성 할 목적으로 반환 된 파일을 무시하고 디렉토리와 함께 모든 파일을 열거합니다.

즉, 계산식을 얻는 데는 지정된 이름을 실제로 검색하는 시간이 소요됩니다.

그래서,이 답변의 목적을 위해 나는 PortableDeviceFolder 클래스 단지 디렉토리 자체를 반환 다른 특성 Folders이 있다고 가정합니다. 그런 재산으로, 우리는 TaW가 제안한 제안을 이용할 수 있습니다.

먼저 해당 카운트를 얻어야합니다. 이 작업을 수행하는 방법은 다음과 같을 것이다 :

private int CountFolders(PortableDeviceFolder rootFolder) 
{ 
    return rootFolder.Folders.Select(folder => CountFolders(folder)).Sum() + 1; 
} 

약간의 지연이있을 것입니다 진행 과정이 표시되기 전에, 물론 위 걸리는 ​​시간을 예측하는 유용한 방법이 없기 때문입니다. 그러나 우리는 모든 파일이 아닌 디렉터리 만 찾고 있기 때문에 상대적으로 간단해야합니다.

처리가 진행되는 동안 진행 상황을 업데이트하려면 별도의 스레드에서 검색을 실행하고 Dispatcher.Invoke()을 사용하여 ProgressBar.Value 속성을 업데이트해야합니다. 검색 방법은 다음과 같습니다

private void SearchFolder(PortableDeviceFolder parent, 
    List<PortableDeviceFolder> result, string fileName, IProgress<int> progress) 
{ 
    foreach (var item in parent.Files) 
    { 
     PortableDeviceFolder folder = item as PortableDeviceFolder; 

     if (folder != null) 
     { 
      SearchFolder(folder, result, fileName, progress); 
     } 
     else if (item.Name.Equals(fileName, StringComparison.OrdinalIgnoreCase)) 
     { 
      result.Add(parent); 
     } 
    } 

    progress.Report(1); 
} 

참고 :별로 참고 문헌 result 매개 변수를 전달하고 왜 나에게 분명하지 않다. 그건 필요하지 않은 것 같아서, 나는 그것을 정기적 인 by-value 매개 변수로 변경했다. 당신의 UI 코드에서

,이처럼 호출 할 수 있습니다 : 여기에 우리가 작업이 수행되는 동안 CountFolders()SearchFolder() 방법은 비동기, UI를 보장하는 것은 반응 남아 모두 실행

private async void SearchFolder_Click(object sender, RoutedEventArgs e) 
{ 
    Button button = (Button)sender; 

    button.IsEnabled = false; 

    string searchPath = textBlock1.Text, searchText = textBox1.Text; 
    List<PortableDeviceFolder> folders = new List<PortableDeviceFolder>(); 
    PortableDeviceFolder rootFolder = new WindowsDirectoryFolder(searchPath); 

    progressBar1.Value = 0; 
    progressBar1.Maximum = await Task.Run(() => CountFolders(rootFolder)); 

    Progress<int> progress = 
     new Progress<int>(increment => progressBar1.Value += increment); 

    await Task.Run(() => SearchFolder(rootFolder, folders, searchText, progress)); 

    listBox1.ItemsSource = folders; 
    button.IsEnabled = true; 
} 

참고.

위의 내용은이 기술을 설명하기 위해 작성한 간단한 WPF 프로그램에서 가져 왔지만 Winforms 나 다른 GUI 프레임 워크에 어려움없이 적용 할 수 있습니다. 기본 아이디어는 동일하게 유지됩니다.