Text-Datei zeilenweise gegen StringArray durchsuchen und Filtern

  • VB.NET

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von Kasi.

    Text-Datei zeilenweise gegen StringArray durchsuchen und Filtern

    Hallo zusammen,

    für mein Problem habe ich bereits eine Code-Lösung, die mir jedoch zu langsam läuft.

    Ich habe als Ausgangsdatei ein Logfile großer Größe - 300.000Lines ... 400.000 Lines .... geht auch größer ;)

    Dazu habe ich ein Textfile mit Suchstrings - ca. 10-15Strings mit Zeilenumbruch getrennt.


    Es soll das Logfile mit den Suchstrings durchsucht werden und die jeweiligen Zeilen, in denen die Suchstrings enthalten sind in ein ein neues Logfile zu schreiben.
    Dabei ist die chronologische Urreihenfolge des Logfiles wichtig.

    Dazu habe ich das Logfile (ASC) und die ItemListe ITEM in je einen ListOfString gelesen und gleiche diese ab.
    Die Chronilogie habe ich damit sichergestellt, dass ich die Jeweilige ASC-Zeile gegen die ITEM Liste abgleiche und bei True in das Filter-Array schiebe.

    VB.NET-Quellcode

    1. For Each line In arrASC
    2. For Each lineItem In arrITEMS
    3. If line.Contains(lineItem) Then arrASCFilter.Add(line)
    4. Next lineItem
    5. Next line


    Das dauert allerding unglaublich lange :sleeping:


    Hat jemand einen Denkanstoss für mich, wie ich da Schwung reinbekomme?
    Willkommen im Forum. :thumbup:

    Bit-Hexer schrieb:

    Dazu habe ich das Logfile (ASC) und die ItemListe ITEM in je einen ListOfString gelesen und gleiche diese ab.
    Wenn Deine Vergleich-Strings in einem Array liegen, ist das in Ordnung.
    Die Log-Datei musst Du nicht in ein Array einlesen, die kannst Du zeilenweise von Platte lesen:

    VB.NET-Quellcode

    1. For Each line in System.IO.File.ReadLines(DEINE_DATEI)
    2. For Each lineItem In arrITEMS
    3. If line.Contains(lineItem) Then arrASCFilter.Add(line)
    4. Next lineItem
    5. Next
    Ob das allerdings schneller läuft, weiß ich nicht.
    Wie lange dauert denn solch ein Lauf (bitte mit beiden Zeilen-Anzahlen)?
    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!
    Versuch mal so ob das schneller ist und ob das Ergebnis passt.

    VB.NET-Quellcode

    1. For Each line in System.IO.File.ReadLines(DEINE_DATEI)
    2. For Each lineItem In arrITEMS
    3. If line.Contains(lineItem) Then
    4. arrASCFilter.Add(line)
    5. Exit For
    6. End If
    7. Next lineItem
    8. Next
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    Bit-Hexer schrieb:

    1000Zeilen/13sec. bei 13 Suchstrings.
    Jou, das erscheinz auch mir langsam.
    LINQ allerdings ist nicht besonders performant.
    Und: Bringr das die gewünschte Reihenfolge?
    ====
    @mrMo Klar, die Suche bei Erfolg abbrechen.
    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!
    Es folgt ein Beispiel.
    Original-Daten kann ich hier nicht einfügen.
    Ich filtere auf Idetifier die in den Zeilen jeweils vorhanden sind.



    8.160530 CANFD 2 Rx a8 1 0 8 8 45 df 1f 80 ff 00 00 00 104453 0 203000 0 42030150 42030150 20000000 20000000
    8.160578 5 144 Rx d 8 69 88 00 00 20 00 00 00 Length = 0 BitCount = 0 ID = 324
    8.160752 CANFD 2 Rx f6 1 0 d 32 4d 0f fd df ff fa 5f ff eb 7f 00 00 00 fd df ff fd 0f 00 7d 00 fa 5f ff eb 1f 00 00 00 00 00 00 213953 0 203000 0 42030150 42030150 20000000 20000000
    8.160979 CANFD 2 Rx 10b 1 0 d 32 d0 08 00 00 00 00 7e fe 00 00 00 00 00 04 ff 01 00 00 00 00 00 00 00 00 00 00 00 00 00 90 24 00 218453 0 203000 0 42030150 42030150 20000000 20000000
    8.161207 CANFD 2 Rx 14a 1 0 d 32 00 00 00 00 f0 03 00 00 00 00 fe 00 00 00 00 00 00 00 00 c0 00 fe df ff 00 00 00 00 00 00 00 00 219453 0 203000 0 42030150 42030150 20000000 20000000
    8.161320 CANFD 2 Rx 700 1 0 8 8 00 00 00 ff ef fe ff ff 104453 0 203000 0 42030150 42030150 20000000 20000000
    8.161363 CANFD 1 Rx cf 1 0 8 8 7b 29 09 a2 3f e4 8a 62 98953 0 203000 0 42030150 42030150 20000000 20000000
    8.161476 CANFD 1 Rx 153 1 0 8 8 00 00 00 ff ef fe ff ff 104453 0 203000 0 42030150 42030150 20000000 20000000
    8.161482 5 131 Rx d 8 00 00 00 C0 00 FE DF FF Length = 0 BitCount = 0 ID = 305
    8.161551 CANFD 2 Rx 200 1 0 d 32 00 e0 3f 48 00 00 00 00 00 0f 00 00 00 24 00 00 00 7f 00 00 00 00 00 00 00 00 00 00 00 00 c0 ff 223140 0 203000 0 42030150 42030150 20000000 20000000
    8.161661 CANFD 2 Rx 86 1 0 8 8 c1 0c b4 21 00 00 00 00 101953 0 203000 0 42030150 42030150 20000000 20000000
    8.161822 5 31E Rx d 8 00 E0 3F 48 00 00 00 00 Length = 0 BitCount = 0 ID = 798
    8.161953 CANFD 2 Rx be 1 0 e 48 74 0f 2f 39 50 00 00 fe 87 b5 1d 64 0a e8 50 2c 00 00 00 80 38 21 4e 00 00 fe 07 fe 9f ff e7 ff fc 1f 00 00 00 fd 00 fd 0f 00 fe e7 7f 7f 52 99 283500 0 203000 0 42030150 42030150 20000000 20000000
    8.161980 CANFD 1 Rx fc 1 0 e 48 a9 02 00 00 7e 00 40 06 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 15 00 00 00 00 00 00 00 00 00 00 f4 01 40 ff eb 7f 0a 88 e3 81 af 42 1f 291453 0 203000 0 42030150 42030150 20000000 20000000
    8.162060 CANFD 2 Rx cf 1 0 8 8 7b 29 09 a2 3f e4 8a 62 98968 0 203000 0 42030150 42030150 20000000 20000000
    8.162068 5 FD Rx d 8 55 D1 1F 81 00 00 00 00 Length = 0 BitCount = 0 ID = 253
    8.162272 CANFD 1 Rx be 1 0 e 48 74 0f 2f 39 50 00 00 fe 87 b5 1d 64 0a e8 50 2c 00 00 00 80 38 21 4e 00 00 fe 07 fe 9f ff e7 ff fc 1f 00 00 00 fd 00 fd 0f 00 fe e7 7f 7f 52 99 283468 0 203000 0 42030150 42030150 20000000 20000000
    8.162311 5 31B Rx d 8 E6 0E 00 00 00 00 00 7E Length = 0 BitCount = 0 ID = 795
    8.162360 CANFD 2 Rx 1C400010 1 0 e 48 a9 02 00 00 7e 00 40 06 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 15 00 00 00 00 00 00 00 00 00 00 f4 01 40 ff eb 7f 0a 88 e3 81 af 42 1f 291468 0 203000 0 42030150 42030150 20000000 20000000
    8.162382 CANFD 1 Rx f7 1 0 8 8 24 07 00 00 c0 84 a0 6c 101968 0 203000 0 42030150 42030150 20000000 20000000
    8.162473 CANFD 2 Rx fd 1 0 8 8 55 d1 1f 81 00 00 00 00 104453 0 203000 0 42030150 42030150 20000000 20000000
    8.162495 CANFD 1 Rx fd 1 0 8 8 55 d1 1f 81 00 00 00 00 104468 0 203000 0 42030150 42030150 20000000 20000000
    8.162583 CANFD 2 Rx f7 1 0 8 8 24 07 00 00 c0 84 a0 6c 101953 0 203000 0 42030150 42030150 20000000 20000000
    8.162773 CANFD 2 Rx 206 1 0 c 24 2a e9 7e 00 00 f8 0f 7a 00 00 00 00 00 00 00 00 08 00 fe 03 00 00 00 00 181468 0 203000 0 42030150 42030150 20000000 20000000
    8.163000 CANFD 2 Rx 14d 1 0 d 32 3f 0c 00 fe 07 00 00 68 fe 07 fe 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 00 3f 218953 0 203000 0 42030150 42030150 20000000 20000000
    8.163068 CANFD 3 Rx 1c400010x 1 0 8 8 03 22 f1 86 55 55 55 55 145125 0 203000 0 42030150 42030150 20000000 20000000
    8.163112 CANFD 2 Rx 31b 1 0 8 8 e6 0e 00 00 00 00 00 7e 103453 0 203000 0 42030150 42030150 20000000 20000000
    8.163224 CANFD 2 Rx 1C400044 1 0 8 8 47 08 e0 00 00 02 04 40 103953 0 203000 0 42030150 42030150 20000000 20000000
    8.163337 CANFD 2 Rx 3c7 1 0 8 8 01 00 10 00 00 00 00 00 104625 0 203000 0 42030150 42030150 20000000 20000000
    8.163389 CANFD 1 Rx 3be 1 0 8 8 47 08 e0 00 00 02 04 40 103953 0 203000 0 42030150 42030150 20000000 20000000
    8.163452 CANFD 2 Rx 3fb 1 0 8 8 00 00 00 00 00 00 00 24 106625 0 203000 0 42030150 42030150 20000000 20000000
    8.163529 5 3BE Rx d 8 47 08 E0 00 00 02 04 40 Length = 0 BitCount = 0 ID = 958
    8.163662 CANFD 1 Rx 3c7 1 0 8 8 01 00 10 00 00 00 00 00 104453 0 203000 0 42030150 42030150 20000000 20000000
    8.163713 CANFD 2 Rx 12dd54aax 1 0 d 32 a7 08 0f 66 da 0e 99 fe bf ff 07 0f 66 02 fe 00 00 00 00 00 30 ae fe 1f 00 00 00 00 00 00 00 00 252109 0 203000 0 42030150 42030150 20000000 20000000
    8.164003 2 1B000015x Rx d 8 00 50 08 01 00 00 00 00 Length = 5217 BitCount = 145 ID = 452984853x
    8.165239 5 391 Rx d 8 FF FF 00 FF FF 25 00 02 Length = 0 BitCount = 0 ID = 913
    8.165728 CANFD 2 Rx c0 1 0 d 32 5f 8c fe e7 7f 10 27 29 e6 7f ff f3 3f ff f3 3f fc 0f 00 00 c0 ff fe 07 00 00 00 00 00 00 00 00 215437 0 203000 0 42030150 42030150 20000000 20000000
    8.166350 CANFD 2 Rx 86 1 0 8 8 a5 0d b4 21 00 00 00 00 101453 0 203000 0 42030150 42030150 20000000 20000000
    8.166368 5 353 Rx d 8 07 0B 54 50 00 20 00 00 Length = 0 BitCount = 0 ID = 851

    Edit: Alles Quatsch, sorry. :whistling:
    Ich habe mal etwas experimentiert:
    Die zu dursuchende Datei und die Datei mit den Suchbegriffen, erst in HashSets einzulesen und dann mit einer einfachen Parallel.ForEach Schleife zu durchlaufen,
    hat das beste Ergebnis zu Tage gebracht.

    ....

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „FormFollowsFunction“ ()

    RodFromGermany schrieb:

    LINQ allerdings ist nicht besonders performant.
    Ich finde, du solltest dieses Gerücht nicht immer wieder in die Welt setzen. Es ist ein Gerücht, weil es eine Halbwahrheit ist.
    Die Ganzwahrheit ist:
    • Linqs Art, viele Elemente durchzuschleifen ist langsamer als eine ForEach-Schleife.
    • Das ist aber vollkommen irrelevant, wenn mit den Elementen jeweils etwas getan wird (und das ist fast immer der Fall)
      Weil das was mit den Elementen getan wird ist meist zig- bis hundertfach langsamer als das Durchschleifen, sodass letzteres nicht mehr messbar wird, weil der Einfluss in anderen Einflüssen (Windows ist kein Echtzeit-System) komplett untergeht.
    Hier mein Versuch, einen fairen Vergleich zu schreiben. Ich lasse die Tests extra mehrmals durchlaufen. Ich vermute, die Windows-Prozessverwaltung stellt sich nach einer Weile auf die Hoch-Last ein und optimiert sich, sodass verschiedene Durchläufe stark unterschiedliche Zeiten erbringen können.
    Wie gesagt: Ich erwarte, dass in dieser systembedingten Invarianz der Unterschied "Linq <-> nichtLinq" komplett (100%) verschwindet:

    VB.NET-Quellcode

    1. Private Sub Benchmarks(fileFullName As String, patternFile As String)
    2. Dim patterns = IO.File.ReadAllLines(patternFile)
    3. Dim lines = IO.File.ReadAllLines(fileFullName)
    4. For i = 0 To 5
    5. Dim sw = System.Diagnostics.Stopwatch.StartNew
    6. Dim selecteds = SelectLinesMrMo(lines, patterns)
    7. System.Diagnostics.Debug.WriteLine($"SelectLines took {sw.ElapsedMilliseconds}ms")
    8. sw.Restart()
    9. selecteds = SelectLinesLinq(lines, patterns)
    10. System.Diagnostics.Debug.WriteLine($"SelectLines2 took {sw.ElapsedMilliseconds}ms")
    11. Next
    12. End Sub
    13. Private Function SelectLinesMrMo(lines As String(), patterns As String()) As List(Of String)
    14. Dim selecteds = New List(Of String)
    15. For Each line In lines
    16. For Each lineItem In patterns
    17. If line.Contains(lineItem) Then
    18. selecteds.Add(line)
    19. Exit For
    20. End If
    21. Next lineItem
    22. Next
    23. Return selecteds
    24. End Function
    25. Private Function SelectLinesLinq(lines As String(), patterns As String()) As List(Of String)
    26. Return Aggregate line In lines Where patterns.Any(AddressOf line.Contains) Into ToList
    27. End Function
    testen kann ichs nicht, ich hab nicht die Daten.

    Das Intelligente von mrMos Ansatz - nämlich die Schleife beim ersten Treffer abzubrechen - das ist in Linq-Any bereits implementiert. Und das ist ja, was scheinbar den deutlichen Performance-Gewinn erbracht hat.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @Bit-Hexer Wenn Du ein paar statistische Untersuchungen machst und dann die Such-Strings im Array nach der Häufigkeit ihres Vorkommens sortierst, kannst Du sicher noch etwas Zeit gewinnen.
    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!
    versuche es mal mit Regex
    siehe größe der Datei und gefundene Zeilen mit dauer der Suche in den Kommentaren

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Dim start As DateTime = DateTime.Now
    3. Using Writer As New System.IO.StreamWriter("E:\TestFolder\HexerErgebnis.txt") 'schreibe suchergebnis in Datei
    4. Using reader As New StreamReader("E:\bible12Backup.txt") 'deine Textdatei zur Suche
    5. 'die Textdatei bible12Backup hat 37,9MB mit 961191 zeilen
    6. Dim sPattern As String = "851|and|God"
    7. 'such Strings mit | getrennt
    8. While Not reader.EndOfStream
    9. Dim line As String = reader.ReadLine()
    10. If Regex.IsMatch(line, sPattern) Then
    11. Writer.WriteLine(line)
    12. End If
    13. End While
    14. End Using
    15. End Using
    16. Dim elapsedTimeInSeconds As Double = DateTime.Now.Subtract(start).TotalSeconds
    17. Debug.WriteLine(" {0} seconds", elapsedTimeInSeconds.ToString)
    18. MsgBox("Fertig!")
    19. 'Zeit = 1,888809: {0} seconds
    20. 'gefundene Zeilen 299968
    21. End Sub