2017-10-22 2 views
1

Ich verwende Directory.GetFiles(), um Dateien in einem Verzeichnis mit mehreren Ordnern zu suchen, und einige dieser Ordner sind zu groß, so dass die Suche bis zu 60 Sekunden dauern kann. Im folgenden Code beginnt eine Suche eine Sekunde nachdem der Benutzer mit der Eingabe aufgehört hat. Dies funktioniert sehr gut, wenn der Benutzer den Dateinamen eingibt und während der Eingabe nicht pausiert, aber wenn er in der Mitte des Wortes pausiert, beginnt die Suche und wird nicht aufhören, bis es fertig ist, auch wenn er/sie wieder zu tippen beginnt.Gibt es eine Möglichkeit, eine Directory.GetFiles Suche zu stoppen

Was ich tun möchte, ist Suchen zu stoppen, während der Benutzer tippt, möglicherweise in der Methode inputFileName_TextChanged.

Gibt es eine Möglichkeit, eine Suche zu stoppen, die bereits gestartet wurde, wenn Directory.GetFiles verwendet wird?

using System.Timers; 
using System.IO; 

namespace findFileTest 
{ 

    public partial class MainWindow : Window 
    { 
     Timer timer = new Timer(); 

     public MainWindow() 
     { 
      InitializeComponent(); 

      timer.Elapsed += new ElapsedEventHandler(TimerEvent); 
      timer.Interval = 1000; 
      timer.Enabled = true; 
      timer.Stop(); 
     } 

     private void inputFileName_TextChanged(object sender, TextChangedEventArgs e) 
     { 
      // How to stop the search currently in process here 
      timer.Stop(); 
      timer.Start(); 
     } 

     public void TimerEvent(object source, ElapsedEventArgs e) 
     { 
      timer.Stop(); 
      findFile(); 
     } 

     private void findFile() 
     { 
      string fName = ""; 

      this.Dispatcher.Invoke(() => { 
       fName = inputFileName.Text; 
      }); 

      var fType = ".txt"; 
      var fileName = fName.Trim() + fType; 

      var file = Directory.GetFiles(@"C:\TestFolder\", fileName, SearchOption.AllDirectories).FirstOrDefault(); 
      if (file == null) { 
       Console.WriteLine("File not found"); 
      } 
      else { 
       Console.WriteLine("Found:" + file); 
      } 
     } 
    } 
} 
+6

Falsche Methode, Directory.EnumerateFiles() ist sehr einfach zu stoppen. Einfach aus der foreach-Schleife ausbrechen. –

+0

Zunächst einmal vielen Dank für Ihren Vorschlag. Wenn ich das richtig verstehe, sollte ich '.FirstOrDefault()' entfernen, mein Suchmuster in * .txt * ändern, damit ich alle Dateien mit der Erweiterung .txt bekommen kann, dann benutze 'foreach', um die Ergebnisse zu durchlaufen. Wenn das richtig ist, was wäre der Vorteil der Verwendung von 'Directory.EnumerateFiles()' anstelle von 'Directory.GetFile()', wenn beide eine Liste von Pfaden zurückgeben, gibt eins 'IEnumerable 'zurück und das andere ein Array von 'string []' aber am Ende denke ich, dass beide gestoppt werden könnten. Was ist der Unterschied? –

+0

@ Peter Duniho hat meine Frage schon beantwortet, danke. –

Antwort

2

Gibt es eine Möglichkeit, eine Suche zu beenden, die bereits begonnen wurde, wenn Directory.GetFiles mit?

Nein, nicht sicher. Die GetFiles()-Methode bietet keinen Mechanismus, um die Arbeit vor der Rückkehr zu unterbrechen. Sie müssten den Thread abbrechen, was viele andere Probleme verursachen würde.

Wie in this comment notiert, würde Ihre Antwort wörtlich die Methode stattdessen verwenden. Diese Methode behandelt die Semantik der zugrunde liegenden FindFirstFile() und FindNextFile(), indem sie einen Enumerator bereitstellt, der jeweils eine Datei zurückgibt. Jedes Mal, wenn eine neue Datei zurückgegeben wird, haben Sie die Möglichkeit, die Aufzählung zu unterbrechen und ohne weitere Arbeit zurückzukehren.

Beachten Sie, dass Sie selbst unter Verwendung von EnumerateFiles() das erste Dateiergebnis nicht erhalten, bis es etwas gefunden hat, das Ihrem Suchmuster entspricht. Wenn Sie zu EnumerateFiles() wechseln, ist es wahrscheinlich, dass Sie auch Ihren eigenen Abgleich für die Eingabe durchführen möchten, anstatt EnumerateFiles() tun zu lassen. I.e. übergeben Sie "*" als Suchzeichenfolge. Dies verlangsamt die gesamte Operation ein wenig, aber Sie können die Operation für jede Datei in dem Suchverzeichnis und den Unterverzeichnissen unterbrechen, statt nur, wenn eine übereinstimmende Datei gefunden wird.

Schließlich schlage ich vor, dass Sie angesichts Ihrer scheinbaren Anwendungsfall, mit der Directory Klasse überhaupt überdenken sollten. Auf der Basis des von Ihnen geposteten Codes starten Sie eine Suche des Dateisystems, eine notwendigerweise langsame Operation, jedes Mal, wenn der Benutzer einen neuen Text eingegeben hat. IMHO wäre es besser, einmal einen Index zu erstellen (z. B. Dictionary<string, List<string>>, der den Dateinamen ohne Erweiterung —, d. H. Path.GetFileNameWithoutExtension() —, auf die vollständigen Pfade jeder übereinstimmenden Datei im Verzeichnis abbildet). Auf diese Weise müssen Sie nichts unterbrechen. Der "Such" -Teil nach dem eingegebenen Text des Benutzers wird nahezu augenblicklich sein.

Es wird natürlich eine anfängliche Verzögerung geben, bevor das Verzeichnis vollständig indiziert ist. Es liegt an Ihnen, wie Sie damit umgehen wollen. Aber ich würde empfehlen, einen Mechanismus bereitzustellen, der dem Benutzer anzeigt, dass die Indizierung nicht vollständig abgeschlossen ist, aber auch die Überprüfung der vorhandenen Datei, nur falls die Datei, nach der der Benutzer sucht, mit einer Datei übereinstimmt, die bereits indiziert wurde.

Beachten Sie, dass die üblichen Windows-Dateisysteme, die — FAT verwendet werden, FAT32, NTFS, usw. — Groß- und Kleinschreibung sind, so dass Sie Ihr Wörterbuch initialisieren mit StringComparer.OrdinalIgnoreCase wollen würde. "Ordinal", da die Dateisystemnamen genau mit den Zeichen übereinstimmen müssen, die ein Benutzer eingibt, und "Groß-/Kleinschreibung ignorieren", damit bei der Suche die Groß-/Kleinschreibung nicht berücksichtigt wird.

Ich würde vermuten, dass es in Ihrem Szenario unwahrscheinlich ist, dass Dateien hinzugefügt oder entfernt werden, während der Benutzer Ihr Programm verwendet, um nach ihnen zu suchen. Wenn Sie jedoch Bedenken in Bezug auf dieses Szenario haben, können Sie entweder dem Benutzer eine Schaltfläche "Aktualisieren" geben, um das Verzeichnis neu zu indizieren, oder FileSystemWatcher verwenden, um den Index automatisch zu aktualisieren, wenn Dateien hinzugefügt oder entfernt werden.

+0

@ Peter Duniho In Ihren ersten beiden Absätzen haben Sie eine Frage beantwortet, warum ich die 'Directory.EnumerateFiles()' anstelle von 'Directory.GetFile()' verwende, danke. Die Idee, eine Indizierung aufzubauen, klingt sehr gut, aber es klingt ein bisschen komplizierter, aber ich werde mich definitiv damit befassen. Schnelle Frage, wie werden indexierte Dateien normalerweise behandelt, Sie erhalten die Wörterbuchliste und speichern sie dann, damit Sie später darauf verweisen können? –

+2

Ja. Die "Liste " ist eine Liste von vollständigen Pfaden aller Dateinamen für einen gegebenen Namen. Z.B. Wenn Sie drei Verzeichnisse mit jeweils einer Datei namens "foo.txt" hätten, dann hätte Ihr Wörterbuch unter dem Schlüssel "foo" eine Liste mit den vollständigen Pfaden dieser drei Dateien. Wenn Sie den Index erstellen, müssen Sie 'TryGetValue()' verwenden, um festzustellen, ob der Schlüssel bereits vorhanden ist. Wenn dies der Fall ist, fügen Sie einfach die neue Datei, die Sie gefunden haben, zur Liste dieses Schlüssels hinzu. Ist dies nicht der Fall, erstellen Sie zuerst die Liste, fügen sie als Wert für diesen Schlüssel hinzu und fügen die neue Datei zur neuen Liste hinzu. –

+0

Es beginnt zu machen Sinn, der Dateiname ohne die Erweiterung wird der Schlüssel und der Pfad wird der Wert in der 'List' sein. Jetzt, nachdem der erste Index fertig ist, werden die meisten Anfragen über die 'List' und nicht über die Suche ausgeführt. Gibt es eine Einschränkung, wie groß die' List' sein kann? Vielen Dank. –

Verwandte Themen