none
File-Server durchsuchen und Dateien auslesen RRS feed

  • Frage

  • Hallo,

    ich habe ein neues Projekt vor, das mir bei der ersten Überlegung schon mal etwas Kopfzerbrechen bereitet. Früher hatte ich schon mal gefragt, bin auch dem einen oder anderen nachgegangen aber habe damals das Ziel nicht weiterverfolgt da kein Anlass mehr dazu bestand.

    Nun ist es wieder aktuell und wird es auch bleiben :-)

    Unser File-Server hat laut den Jungs des Infrastruktur-Team mehr als 35 Milionen Dateien, konnte ich erst gar nicht glauben. Das Ziel ist alle Dateien auf dem File-Server durchzugehen bzw nur Dateien miti einer bestimmten Endung zu berücksichtigen. In dieser Datei müssen diverse Angaben ausgelesen und in einer SQL-Datenbank abgelegt werden.

    Das Problem mit dem ich als erstes konfrontiert bin, bei diversen Umorganisationen bzw umhängen/umbenennen der Dateien und Pfade sind mittlerweile Tiefe Pfade entstanden, diese sind länger als die erlaubten Längen für 240 Zeichen nur Pfad und/oder 256 Zeichen für Pfad und Dateiname. Hier stolpern die Funktionen von .NET Framework und ich muss hier die Dateien direkt über die entsprechenden API´s ansprechen.

    Nun möchte ich bei 35.000.000 Dateien vermeiden das sich das Tool "verschluckt", einfriert oder ungünstigenfalls abstürzt und neu gestartet werden muss.

    Daher wäre mir sehr an Euren Erfahrungen gelegen wie ich hier am besten vorgehen kann.

    Mit schwebt vor die Dateien nur über API-Zugriff zu suchen und zu öffnen, hier können ja dann über (geschätzt) 32.000 Zeichen möglich sein.

    Weiter möchte ich mit einem FiFo-Puffer arbeiten, so kann ich die Dateien in einem Prozess suchen und in eine Liste einreihen und über einen zweiten und unabhängigen Prozess auslesen. Der erste Prozess soll aber pausieren sobald zuviele auszulesende Dateien im FiFo-Puffer eingereiht sind.

    Wie geht Ihr hier bei einer solchen Aufgabenstellung vor?

    Hättet Ihr mir dazu etwas Beispiel-Code etc?

    Viele Grüsse,
    Maximilian

    Freitag, 20. September 2013 17:32

Antworten

  • Hallo Maximilian,

    zum 2. Teil, dem Abarbeiten der gefundenen Files, würde ich mal überlegen, ob es überhaupt sinnvoll ist, mit Queue und 2. Thread zu arbeiten. Das würde ja nur was bringen, wenn die Dateioperationen wirklich auch parallel verarbeitet würden. Das kann zwar Windows prinzipiell inzwischen und auch die NCQ-Fähigkeiten moderner Festplatten sind da unterstützend, aber bei der massiven I/O-Last, die Dein Programm erzeugt, würde das nur bei SSDs oder mehreren physikalischen Platten überhaupt was bringen. Ansonsten spuckt Dir die Plattenphysik massiv in die Suppe und die Versuche einer Parallelisierung können das ganze System verlangsamen, besonders blöd bei einem Server.

    Die Alternativen wären a) die direkte Bearbeitung jeder Datei, sobald sie gefunden wurde oder b) alle gefundenen Dateien in eine Liste und dann abarbeiten.

    Willst Du doch mit der Queue und dem 2. Thread arbeiten, würde ich mir es einfach machen und auf beiden Seiten mit Polling des Queue-Counts arbeiten. Das ist in Deinem Fall harmlos, weil Du in den Polling-Schleifen mit langen SLEEPs die Threads pausieren kannst, ohne dass das im Ablauf spürbar ist. Beispielsweise pausiert der Schreib-Thread, sobald die Queue 1000 Einträge überschreiten will und macht weiter, wenn 500 unterschritten werden. Den Thread auf der Lese-Seite startest Du vom 1. Thread aus, sobald der erste Eintrag in der Queue ist und der pausiert immer, solange die Queue leer ist.

    Gruß,

    Winfried

    • Als Antwort markiert MaxiTesch Dienstag, 24. September 2013 20:07
    Sonntag, 22. September 2013 07:04

Alle Antworten

  • Hallo,

    wenn Du versuchen würdest auf meinen Servern Dateien zu suchen(in dieser Menge) würde ich dir die Freundschaft kündigen. Alle relevanten Dateien sollten vorher schon in einem Pfad abgelegt sein.

    Abgesehen das Dir höchster Wahrscheinlichkeit die Rechte fehlen und Deine Anwendung von einer in die andere Execption "solpert".

    Gruß Scotty

    Gruß Scotty

    Freitag, 20. September 2013 18:06
  • Hi Scotty,

    also, ich suche natürlich nur in Absprache mit den Jungs aus der Infra-Abteilung, das ist ja klar :-)

    Ich möchte "nur" Dateien des Typ *.ezk suchen/ansprechen, daher der erste Prozess welcher die Liste gefundener Dateien bereitstellt (FiFo-Liste). Der  zweite Prozess soll sich dann der Liste bedienen und die Dateien öffnen und auslesen.

    Die Dateien sind eigentlich umbenannte ZIP-Archive die ich öffnen und 5 Dateien auslesen muss, diese sind dann wiederum XML-Dateien und in allen EZK-Dateien enthalten (unter anderem).

    Das Tool wird auf dem Server dann mit den entsprechenden Rechten zum auslesen der Dateien gestartet, das dann nicht von mir.

    Ich werde das Tool erst mal nur auf meinem Desktop schreiben und testen, erst wenn das fertig ist geht es in die Infra-Abteilung.

    Das es nicht einfach sein wird haben mir die Jungs schon mitgeteilt, so ist es nicht.

    Damit wir aber so wenig wie irgend möglich Probleme bekommen oder das Tool bei 60% abstürzt, wollte ich mal hier nach Ideen nachfragen.

    Sollten Exceptions geworfen werden, wird das natürlich soweit abgefangen und in einem Logfile protokolliert, die Dateinamen inkl Pfad werden dabei in eine andere Datei geschrieben damit man diesen in einem zweiten Schritt nachgehen kann.

    Ich möchte angesichts von 35 Milionen Dateien alles richtig machen, sowas hatte ich noch nie und ich möchte da ja nichts unversucht lassen das Tool zu stabilisieren.

    Viele Grüsse,
    Maximilian


    • Bearbeitet MaxiTesch Freitag, 20. September 2013 18:20 Fehler korrigiert
    Freitag, 20. September 2013 18:18
  • Hallo,

    rekursive Dateisuche hab ich in DotNet zwar noch nicht gemacht, aber in anderen Sprachen. Für jedes Verzeichnis, das Du findest, rufst Du einfach die Suchroutine rekursiv wieder auf. Die überlangen Pfade sollten eigentlich kein Problem darstellen, wenn Du immer relativ bleibst, also immer das Default-Verzeichnis mit wechselst. Fifo (also Queue) und Threading sind glücklicherweise in VBNet bequem zu verwenden. Du musst natürlich im Thread auf der Lese-Seite des Fifos auch wieder mit relativen Pfaden die Dateien öffnen. Der Such-Thread legt sich schlafen, sobald Fifo.Count beim Schreiben eine bestimme Zahl überschreitet und wird vom Lese-Thread wieder geweckt, wenn eine Zahl unterschritten wird.

    Gruß,

    WiWo


    • Bearbeitet WiWo Freitag, 20. September 2013 20:22
    Freitag, 20. September 2013 20:19
  • Hallo Maximilian,

    	Private Sub Main()
    
    		Dim results As New List(Of IO.FileInfo)
    		Dim indent = -2
    
    		For Each drive In IO.DriveInfo.GetDrives
    			ScanFiles(indent, New IO.DirectoryInfo(drive.Name), results)
    		Next
    
    
    		Console.ReadKey()
    
    	End Sub
    
    	Private Sub ScanFiles(indent As Integer, parent As IO.DirectoryInfo, results As List(Of IO.FileInfo))
    		indent += 2
    		'Console.WriteLine(String.Format("{0}Scanning: '{1}'", New String(" "c, 2), parent.FullName))
    		Try
    			For Each fileInfo In parent.GetFiles(".ezk")
    				results.Add(fileInfo)
    			Next
    		Catch ex As Exception
    			Console.WriteLine(String.Format("{0}EXCEPTION: '{1}'", New String(" "c, 2), ex.Message))
    		End Try
    
    		Try
    			For Each directoryInfo In Parent.GetDirectories
    				ScanFiles(indent, directoryInfo, results)
    			Next
    		Catch ex As Exception
    			Console.WriteLine(String.Format("{0}EXCEPTION: '{1}'", New String(" "c, 2), ex.Message))
    		End Try
    		indent -= 2
    
    	End Sub
    

    Viel Spass beim Testen. Bevor Du das über Serverlaufwerke laufen lässt informiere den Administrator was Du vor hast.

    Bedenke das auch Test auf einem lokalen System gemappte Laufwerke haben können. Diese werden im obigen Beispiel ebenfalls durchsucht.

    Gruß Scotty

    Samstag, 21. September 2013 05:52
  • Hi WiWo,

    die Schlagworte Queue und Threading gehen schonmal in die Richtung die ich schon mal vor Monaten nachgeschlagen hatte.

    Einzige war mir damals (und heute) das Zusammenspiel nicht klar wie ich beide Prozesse aufeinander abstimmen kann.

    Theoretisch muss der erste Prozess warten/schlafen und wieder loslaufen wenn die Queue voll ist oder wieder bereit steht um EInträge aufzunehmen, der zweite Prozess muss so lange laufen wie der erste Prozess Daten liefern kann.

    Das Zusammenspiel war mir nicht so klar, ich muss nochmal nach Infos dazu suchen, die waren nicht so umfangreich, wenn ich mich noch richtig erinnere.

    Ein grosses Problem wird sein auf die Datei zuzugreifen, denn ist der Pfad und Dateiname länger als 256 Zeichen, dann habe ich mit den Funktionen vom Framework Probleme die Datei zu lesen, wie ich noch weiss wird dann eine Exception geworgen (Path too long).

    Hast Du Dich mit Queues und dem Threading näher beschäftigt und kannst mir dazu Tipps geben?

    Viele Grüsse,
    Maximilian


    PS: Ist mir jetzt gerade erst aufgefallen das Du den Pfad jeweils wechseln würdest, das ist eine gute Idee :-)
    • Bearbeitet MaxiTesch Samstag, 21. September 2013 06:22 Nachtrag
    Samstag, 21. September 2013 06:17
  • Hi Scotty,

    Danke für das Script :-)

    Wegen dem Admin, der zuständige Kollege aus dem Team der Infrastruktur darf das Tool dann selber starten, ich will es nur soweit bauen. Das mache ich nicht im Alleingang, betrete niemals den Garten eines anderen Admin :-)

    Viele Grüsse,
    Maximilian

    Samstag, 21. September 2013 06:20
  • Hallo Maximilian,

    zum 2. Teil, dem Abarbeiten der gefundenen Files, würde ich mal überlegen, ob es überhaupt sinnvoll ist, mit Queue und 2. Thread zu arbeiten. Das würde ja nur was bringen, wenn die Dateioperationen wirklich auch parallel verarbeitet würden. Das kann zwar Windows prinzipiell inzwischen und auch die NCQ-Fähigkeiten moderner Festplatten sind da unterstützend, aber bei der massiven I/O-Last, die Dein Programm erzeugt, würde das nur bei SSDs oder mehreren physikalischen Platten überhaupt was bringen. Ansonsten spuckt Dir die Plattenphysik massiv in die Suppe und die Versuche einer Parallelisierung können das ganze System verlangsamen, besonders blöd bei einem Server.

    Die Alternativen wären a) die direkte Bearbeitung jeder Datei, sobald sie gefunden wurde oder b) alle gefundenen Dateien in eine Liste und dann abarbeiten.

    Willst Du doch mit der Queue und dem 2. Thread arbeiten, würde ich mir es einfach machen und auf beiden Seiten mit Polling des Queue-Counts arbeiten. Das ist in Deinem Fall harmlos, weil Du in den Polling-Schleifen mit langen SLEEPs die Threads pausieren kannst, ohne dass das im Ablauf spürbar ist. Beispielsweise pausiert der Schreib-Thread, sobald die Queue 1000 Einträge überschreiten will und macht weiter, wenn 500 unterschritten werden. Den Thread auf der Lese-Seite startest Du vom 1. Thread aus, sobald der erste Eintrag in der Queue ist und der pausiert immer, solange die Queue leer ist.

    Gruß,

    Winfried

    • Als Antwort markiert MaxiTesch Dienstag, 24. September 2013 20:07
    Sonntag, 22. September 2013 07:04
  • Hallo zusammen,

    ich werde mir das ganze in der kommenden Woche anschauen, da habe ich Home-Office und dafür mehr Zeit.

    Ob Queue und 2. Thread ist mir nicht wichtig, auch wenn das Programm sicher mehr als eine Woche zum durchgehen aller Dateien braucht ist nicht wichtig, was aber wichtig ist, es sollte stabil sein und nicht bei 80% abbrechen :-)

    Ich schaue es mir nächste Woche an und hoffe das ich Euch nochmal nerven darf wenn was nicht klappt.

    Viele Grüsse,
    Maximilian

    Dienstag, 24. September 2013 20:07
  • Hallo Maximillian,

    bei der von Dir veranschlagten Laufzeit würde ich auf jeden Fall Suchlauf und Abarbeitung trennen, sogar in verschiedene Programme. Die Liste der gefundenen Dateien würde ich selber als Datei speichern, die dann vom anderen Teil abgearbeitet wird. Verarbeitete Einträge kriegen dabei eine Kennung (am besten einen Timestamp, dann kann man gleich das Laufzeit-Verhalten erkennen). Das Programm kann dann selbst noch sicher arbeiten, wenn zwischenzeitlich der Server mal runtergefahren wird.

    Gruß,

    Winfried

    Mittwoch, 25. September 2013 08:51