"FindInFiles" mit einer konkreten Datei möglich?

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    "FindInFiles" mit einer konkreten Datei möglich?

    Vielleicht kann mir hier wieder geholfen werden ^^.

    Ich habe ein recht umfangreiches Programm erstellt, dass mir jetzt eine Harcke ins Kreuz schmeißt 8| X(
    Gibt es eine ebenso einfache Funktion wie "My.Computer.FileSystem.FindInFiles", nur auf konkret eine Datei bezogen?

    Weil diese Datei befindet sich in einem Ordner mit vielen Dateien (und will und darf dort nichts rum kopieren)!
    Ich dachte (leider) dass ich diese geniale Funktion aufrufen kann, mit Filter auf eine konkrete Datei. Leider akzeptiert die Funktion aber nur Ordnerangaben :pinch: ;(

    Ich suche sowas wie: My.Computer.FileSystem.FindInOneFile(<Datei>,<Suchtext>)

    Vielen Dank im Voraus,
    LG, Hinti
    Du möchtest also einen Text im Inhalt einer Datei suchen?
    Dann solltest Du per System.IO.File.ReadAllText(Pfad, System.Text.Encoding.Default) den Inhalt der Datei in eine Variable laden und dann per .Contains(Suchtext) prüfen, ob der Suchtext enthalten ist. Beziehungsweise mit .IndexOf(Suchtext) erhältst Du die Position des Suchtextes in der Datei. -1 wird zurückgegeben, wenn der Text nicht enthalten ist.
    Das liese sich noch mit Streams optimieren, ist aber nicht wirklich nötig.

    Nochwas:
    Den My-Namespace solltest Du meiden. Eine Ausnahme ist My.Resources.
    Verwende die entsprechenden .Net-Klassen. Siehe auch:
    [VB 2010] Böses aus VB6/VB2003 - und die richtigen VB.NET-Alternativen
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Danke Niko, das hat mir geholfen. Super 8o

    Noch eine Frage weil du das mit Streams optimieren angesprochen hast. Ich habe eine Spezialsuche geschrieben, die uns bei bestimmten Dateistrukturen hilft, ja nun - eben beim suchen von Text in Dateien.

    Nun gibt es die Variation, das bis zu 3700 Dateien jeweils dann mittels .ReadAllText und anschliessendem .Contains durchsucht werden. Das zwingt natürlich in die Knie und dauert eine Weile. Aber es funktioniert :rolleyes:.

    Meintest du mit "Streams - Optimierung" etwa sowas wie in Sachen Performance? :whistling:
    *ziemlich neugierig bin + sowas gut brauchen könnt*
    Nicht ganz Performance. Also schon, aber auch nicht... Ich erklär's mal.
    Ein Stream, oder besser gesagt, ein FileStream erfordert es nicht, dass die komplette Datei auf einen Schlag eingelesen wird.
    Dadurch schont man den Arbeitsspeicher. Allerdings kann es sein, dass dadurch die Prozessorauslastung steigt. Kommt halt drauf an. Bei extrem großen Dateien ist es sicher besser, Streams zu verwenden. Bei kleineren Dateien (das dürfen gerne mehrere MB sein), ist es praktischer, System.IO.File.ReadAllText() zu verwenden. Denn da würde sich die Optimierung nicht lohnen.

    Übrigens:
    System.IO.File.ReadAlltext läuft intern auch nur über Streams.

    VB.NET-Quellcode

    1. 'SR ist ein intern deklarierter StreamReader
    2. Dim Buffer = New Char(4095) {} 'Ein Puffer mit Platz für 4096 Zeichen.
    3. Dim SB As New StringBuilder(4096)
    4. Dim CharCount As Integer
    5. Do
    6. CharCount = SR.Read(Buffer, 0, 4096)
    7. If CharCount = 0 Then
    8. Exit Do
    9. End If
    10. SB.Append(Buffer, 0, CharCount)
    11. Loop
    12. Return SB.ToString()


    Wie man erkennt, werden immer nur 4KB auf einmal verarbeitet. Da könnte man die Optimierung ansetzen. Man liest immer 4KB aus sucht nach und nach, ob der Suchstring darin vorkommt. Das Problem ist hierbei eben, dass der Suchstring nicht genau in einem Block vorkommen muss, oder größer sein kann. Das Laden der Blöcke richtig hinzubekommen, ist gar nicht so einfach. Da muss man ordentlich Hirnschmalz reinstecken ;)
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Niko Ortner“ ()

    Bei größeren Dateien könnte man auch bequem File.ReadLines(filename) verwenden. Nicht zu verwechseln mit File.ReadAllLines(filename).
    Das lässt sich schön bequem handeln, man hat keine Streams, und trotzdem wird nur das eingelesen was man braucht.
    Die Zeilen werden bei File.ReadLines(filename) nämlich erst zu dem Zeitpunkt eingelesen, wenn sie auch wirklich an der Reihe sind.
    Das könnte bei sehr großen Dateien von Vorteil sein, wenn schon nach wenigen Zeilen das Einlesen abgebrochen werden kann.
    Solange das Searchpattern sich nicht über mehr als eine Zeile erstreckt ist das ideal.

    VB.NET-Quellcode

    1. For Each line In File.ReadLines(filename)
    2. If line.Contains(search) Then
    3. '...
    4. Exit For
    5. End If
    6. Next


    Collections.Generic.IEnumerable(Of T) FTW
    Und das alles ohne Hirnschmalz ;)

    €: Wenn man aber alle Treffer haben will und nicht nur die Information ob der Begriff enthalten ist, kommt man um ein komplettes Einlesen nicht drumrum.

    Da ich annehme, dass du dich nicht nur an Contains() interessierst, sndern auch am Suchtreffer, werfe ich mal ReadAllText + Regex in den Raum. Mit Regex kann man alles auf einmal erschlagen (wenn mans ungünstig macht, auch die Performance).

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „markus.obi“ ()

    File.ReadLines(filename)Also ich danke Euch vielmals für diese tollen Anregungen. Zunächst habe ich es mit "ReadAllText" und "Contains" realisiert. Für mich ideal, weil ich nur daran interessiert bin, ob es überhaupt enthalten ist.

    Wenn ich die Optionen dann so setze, das der Filter etwa 100 Dateien die zu Durchsuchen sind ergibt, geht es halbwegs "ratz fatz". Ohne Filter bei bis zu 3700 Dateien muss man schon deutlich unangenehm warten. Gut das ist nicht so schlimm. Aber ich werde wenn ich Zeit finde, noch einige Tests mit euren Vorschlägen machen. Mal sehen.

    Danke jedenfalls ^^ :thumbsup:

    Achso, Nachtrag:
    Die Textdateien um die es sich handelt, sind alle so zirka 500 KB groß. Viele eher noch deutlich kleiner.
    Die Sucheinträge sind nie Zeilenübergreifend. Deshalb werde ich mal zum Zeitvergleich die File.ReadLine(xxx) testen.

    Hinti schrieb:

    zum Zeitvergleich
    Meinst Du ReadAllLines()?
    Das ist dem Lesen egal, die ganze Datei wird gelesen.
    Das programminterne Handling hingegen ist anders, denn Du musst mit For Each alle Zeilen abarbeiten, und das stellt bei vielen Dateien durchaus einen Overhead dar.
    Hier musst Du Dich davon leiten lassen, was das Ziel Deiner Anstrengungen ist, der einfache Check auf Vorhandensein oder die Position oder die Zeile und die Position.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also Dank Euch, habe ich ein tolles Ergebnis erreicht.

    Mit Zeitvergleich meinte ich, ich messe die Zeit die ich brauche, um in beispielsweise 200 meiner Files mit der Variante ReadLines (Zeilenweises lesen bis "Text" gefunden wird), zu suchen. Oder Alternativ, wieviel Zeit ich brauche wenn ich die Variante "ReadAllText" - Contains, verwende.

    Und was soll ich sagen, der Zeitvorteil ist enorm hoch. Ich hab viele der dann gängigen Suchvariationen angewendet. Die Variante ReadLines bis zum ersten Auffinden eines Textes, läuft stets um weit jenseits der 50 Prozent schneller. Also in meinem Fall ein klarer Fall für ReadLines! (Im Vergleich zu ReadAllText)

    Und nochwas. Als ich GetFiles ersetzt habe durch "Directory.EnumerateFiles", bekam ich nochmals mindestens 50% Zeitvorteil. Bist du deppat kann man da viel rausholen :D

    In Summe habe ich bei Suchen die zuvor mit "GetFiles" + "ReadAllText" an die 20 Sekunden gedauert haben, nun in 2 Sekunden geschafft 8o 8o 8o 8o
    Definiere

    Hinti schrieb:

    50% Zeitvorteil
    :D
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!