Textdateien Inhalt vergleiche und blockweise bei nicht vorhandensein in neue TXT kopieren

  • VB.NET

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von samson.

    Textdateien Inhalt vergleiche und blockweise bei nicht vorhandensein in neue TXT kopieren

    Moin Zusammen,

    ich stehe vor einem Problem und komme mit dem Knoten im Kopf einfach nicht alleine klar...
    Folgendes Szenario...
    Aus einem Konvertierungsprogramm für ein Arzt Informationssystem erhalte ich eine "BDT"-Datei diese ist rein Text und muss verglichen werden.

    Beispiel:
    Textdatei 1 hat folgenden Inhalt:
    Spoiler anzeigen

    0173050Standard
    017620020180630
    01362010800
    01362021800
    0157202XXXXXX
    017620020180630
    01362010800
    01362021815
    0157202XXXXXX
    017620020180630
    01362010800
    01362021815
    0157202XXXXXX
    017620020181205
    01362010845
    01362020900
    0153000476064
    0217201Muster, Max
    0227202Kontrolle /us
    017620020191005
    01362010800
    01362021800
    0157202XXXXXX

    Die Datei hat im Orignial jedoch ~45 MB und beinhaltet ~2,5 Mio. Zeilen

    Nun gab es bei der ersten Konvertierung einen Fehler vom System und hat mir nicht alle Zeilen übernommen. Zwischen drin fehlen diverse Zeilen.
    Es soll nun die neue Datei, die alle Daten beinhaltet mit der alten Datei verglichen werden.
    Bei fehlenden Einträgen soll es "Blockweise" (Spoiler Beispiel 2) in eine neue Textdatei geschrieben werden.

    Spoiler2
    Spoiler anzeigen

    Start Block bei Feldkennung 6200, die ersten 3 Zahlen sind Prüfziffern mit der gesamten Zeilenlänge + 2 Zusatzzeichen
    017620020180630
    01362010800
    01362021800
    0157202123456
    0157202abcdef
    0157202ghijkl


    Der Start für einen Block ist immer Feldkennung 6200
    danach können beliebig viele Zeilen folgen.
    Somit muss von 6200 bis 7202 gesucht und kopiert werden.

    Dieser Block muss dann mit der alten Textdatei verglichen werden. Ist dieser nicht vorhanden, soll er in eine Textdatei geschrieben werden.

    Hat da jemand eine Idee wie ich das am sinnvollsten umsetzen kann?
    Am besten Quick 'n Dirty ;) Es muss kein "Kundenprogramm" sein, sondern soll einfach für mich als Ziel dienen.

    Danke :)

    Stefan
    Nein! Doch! OHH!

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

    samson schrieb:

    Es soll nun die neue Datei, die alle Daten beinhaltet mit der alten Datei verglichen werden.
    Warum verwirfst Du nicht die alte Datei und verwendest die neue?
    Willst Du System-Fehler erkennen?
    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!
    Moin @RodFromGermany,
    im Grundsatz würde ich sage ja,... Gibt da aber ein kleiner Haken an der Sache.
    Bei der Konvertierung ist es nicht aufgefallen, erst hinterher im Kundensystem.
    Nun fehlt die Hälfte der Daten (Es sind die Patiententermine einer Arztpraxis)
    Ich versuche es irgendwie grade zu biegen aber ein paar Millionen Zeilen einer BDT Datei zu lesen und zu vergleichen macht händisch auch kein sinn.
    Kurzum: Der Hersteller des Konverters hat nachgebessert, nun muss die Differenz gefunden werden und nachgeschoben werden ins System.
    Daher der riesen Aufwand.
    Nein! Doch! OHH!

    samson schrieb:

    Somit muss von 6200 bis 7202 gesucht und kopiert werden.
    Dein Spoiler2-Beispiel weist aber mehrere 7202-Zeilen auf. Was soll mit den Zeilen nach dem ersten Auftreten von 7202 passieren? Und: Können die Erkennungszahlen fälschlicherweise an anderer Stelle innerhalb einer Zeile auftauchen, also z.B. 0157202166200?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed Ich kann es dir nicht wirklich beantworten.
    Das Vorkommen der "Feldkennung" innerhalb des "Inhaltbereich" wäre denkbar.
    Wenn mehr als einmal 7202 vorkommt, muss es markiert sein bis zum letzten vorkommen in der Gruppierung.

    Zur Erklärung: Der augenscheinliche "Datenmüll" nennt sich BDT Format.
    Prüfziffer
    Feldkennung
    Inhalt
    017
    6200
    20180630
    013
    3201
    0800
    013
    6202
    1800
    015
    7202
    XXXXXX

    Rein von der Theorie wäre folgendes Szenario denkbar.
    ReadAllLines (Menge Rechenleistung bei 4,5 Mio Zeilen und einer Dateigröße um die 44MB notwendig)
    > Zeilenweise die ersten 3 Stellen ignorieren
    > die nächsten 4 Stellen vergleichen bis 6200 kommt und Stelle merken
    > weitersuchen bis das letzte Vorkommen 7202 gefunden wird und die Markierung von Position A bis Position B durchführen.

    Bisher hat aber keiner meiner Ansätze funktioniert, habe das Projekt schon 4x gelöscht... Sitze gerade an Versuch 5.
    (Bisher hab ich nur die OpenFileDialog stehen 8| )

    Grüße Stefan
    Nein! Doch! OHH!
    ich versteh immer noch nicht genau. Mach doch mal ein Input-Output-Beispiel.
    Also bei der Eingabe Text1=... Text2=... - soll ergeben Text3=...

    Ich könnte mir zusammenreimen, dass du Text1 in Text2 einmergen willst.
    Also Datensätze, die nur in Text1 vorkommen, sollen übertragen werden.
    Hingegen Datensätze, die in beiden Dateien sind, braucht man ja nicht mehr übertragen.

    Ist technisch nicht sooo kompliziert. Man muss halt den bmt-Byte-Salat in Datensätze organisieren.
    Wenn ich richtig liege eine Zusatzfrage: Ist die Reihenfolge der Datensätze relevant, oder reicht es, die fehlenden hinten anzuhängen?

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

    Der Ablauf passt. Vermutlich so:

    Quellcode

    1. ErfasseDaten = False
    2. DatenendeInSicht = False
    3. BisherigeDaten = Nix
    4. Von 1. bis letzter Zeile
    5. Wenn EndZifferErkannt, dann DatenendeInSicht = True
    6. Wenn DatenendeInSicht Und aktuelleZeile enthält keine Endprüfziffer, dann
    7. DatenendeInSicht = False
    8. BisherigeDaten In Datei schreiben
    9. BisherigeDaten löschen
    10. ErfasseDaten = False
    11. End Wenn
    12. Wenn StartprüfzifferErkannt, dann ErfasseDaten = True
    13. Wenn ErfasseDaten, dann BisherigeDaten += aktuelleZeile
    14. Nächste Zeile

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @ErfinderDesRades Du hast es erfasst.
    Jedoch soll er die Daten, die aus der ersten Konvertierung stammen mit der neuen Datei vergleichen.
    Wenn dann etwas fehlt, was nur "Blockweise durch Anfang und Ende" vergleichbar ist, soll er dies in eine extra TextBox oder direkt in eine Datei schreiben.
    ok, Ausgabe in TB oder File ist jetzt kein Hexenwerk, jedoch bekomm ich die beiden Dateien nicht verglichen.

    @VaporiZed da wäre die Geschichte siehe Oben. Ich kann es nicht Zeilenweise vergleichen, das hätte ich schon längst gemacht, wäre einfach.
    Ich muss erst den "Datensatzblock" herausfinden, diesen dann in der anderen Datei / Textbox suchen und dann prüfen ob vorhanden = ok oder schreiben
    Nein! Doch! OHH!
    Wenn die Daten nicht wie in Spoiler#1 vorliegen, wie dann? Alles als Block, also

    Quellcode

    1. 0173050Standard01762002018063001362010800013620218000157202XXXXXX01762002018063001362010800013620218150157202XXXXXX01762002018063001362010800013620218150157202XXXXXX017620020181205013620108450136202090001530004760640217201Muster, Max0227202Kontrolle /us01762002019100501362010800013620218000157202XXXXXX
    Wenn doch zeilenweise wie Spoiler1, dann seh ich in meinem Pseudocodevorschlag das Problem nicht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed Dein Pseudocodevorschlag ist gut, daran zweifel ich nicht. Ich zweifel gerade an mir selber... Ich bekomms gerade nicht mal gebacken die Textdatei auszulesen... Ich fass es nicht. Die Form friert mir ständig ein.
    Ich glaub ich lass es bleiben... Bin nicht fit genug für sowas anscheinend.
    Nein! Doch! OHH!
    Ich hab nochmal Datensätze erstellt.
    Vollständige Datei
    Unvollständige Datei
    Was fehlt...
    017620020231204
    01362011200
    01362022330
    0157202XXXXXX
    017620020231205
    01362010800
    01362021000
    0157202XXXXXX
    017620020231205
    01362011000
    01362021200
    0147201IGEL,
    0247202PRP + OD + ESTW
    0157202XXXXXX
    017620020231205
    01362011200
    01362021400
    0157202XXXXXX
    017620020231206
    01362010800
    01362021930
    0157202XXXXXX
    017620020231207
    01362010800
    01362021930
    0157202XXXXXX
    017620020231208
    01362010800
    01362020900
    0157202XXXXXX
    017620020231208
    01362011200
    01362022330
    0157202XXXXXX
    017620020231209
    01362010800
    01362021930
    0157202XXXXXX
    017620020231211
    01362010800
    01362020900
    0157202XXXXXX
    017620020231211
    01362011200
    01362022330
    0157202XXXXXX
    017620020231212
    01362010800
    01362021000
    0157202XXXXXX
    017620020231212
    01362011000
    01362021200
    0147201IGEL,
    0247202PRP + OD + ESTW
    017620020231212
    01362011200
    01362021400
    0157202XXXXXX
    017620020231213
    01362010800
    01362021930
    0157202XXXXXX
    017620020231214
    01362010800
    01362021930
    0157202XXXXXX
    017620020231215
    01362010800
    01362020900
    0157202XXXXXX
    017620020231215
    01362011200
    01362022330
    0157202XXXXXX
    017620020231216
    01362010800
    01362021930
    0157202XXXXXX
    017620020231218
    01362010800
    01362020900
    0157202XXXXXX
    017620020231218
    01362011200
    01362022330
    0157202XXXXXX
    017620020231219
    01362010800
    01362021000
    0157202XXXXXX
    017620020231219
    01362011000
    01362021200
    0147201IGEL,
    0247202PRP + OD + ESTW
    017620020231219
    01362011200
    01362021400
    0157202XXXXXX
    017620020231220
    01362010800
    01362021930
    0157202XXXXXX
    017620020231221
    01362010800
    01362021930
    0157202XXXXXX
    017620020231222
    01362010800
    01362020900
    0157202XXXXXX
    017620020231222
    01362011200
    01362022330
    0157202XXXXXX
    017620020231223
    01362010800
    01362021930
    0157202XXXXXX
    017620020231225
    01362010800
    01362020900
    0157202XXXXXX
    017620020231225
    01362010900
    01362021200
    0177202Feiertag
    017620020231225
    01362011200
    01362022330
    0157202XXXXXX
    017620020231226
    01362010800
    01362021000
    0157202XXXXXX
    017620020231226
    01362011000
    01362021200
    0177202Feiertag
    017620020231226
    01362011200
    01362021400
    0157202XXXXXX
    017620020231226
    01362011400
    01362021730
    0177202Feiertag
    017620020231227
    01362010800
    01362021930
    0157202XXXXXX
    017620020231228
    01362010800
    01362021930
    0157202XXXXXX
    017620020231229
    01362010800
    01362020900
    0157202XXXXXX
    017620020231229
    01362010900
    01362021200
    0157202Urlaub
    017620020231229
    01362011200
    01362022330
    0157202XXXXXX
    017620020231230
    01362010800
    01362021930
    0157202XXXXXX
    017620020231204
    01362011200
    01362022330
    0157202XXXXXX
    017620020231205
    01362010800
    01362021000
    0157202XXXXXX
    017620020231207
    01362010800
    01362021930
    0157202XXXXXX
    017620020231208
    01362010800
    01362020900
    0157202XXXXXX
    017620020231208
    01362011200
    01362022330
    0157202XXXXXX
    017620020231209
    01362010800
    01362021930
    0157202XXXXXX
    017620020231211
    01362010800
    01362020900
    0157202XXXXXX
    017620020231211
    01362011200
    01362022330
    0157202XXXXXX
    017620020231212
    01362010800
    01362021000
    0157202XXXXXX
    017620020231212
    01362011000
    01362021200
    0147201IGEL,
    0247202PRP + OD + ESTW
    017620020231212
    01362011200
    01362021400
    0157202XXXXXX
    017620020231213
    01362010800
    01362021930
    0157202XXXXXX
    017620020231214
    01362010800
    01362021930
    0157202XXXXXX
    017620020231215
    01362010800
    01362020900
    0157202XXXXXX
    017620020231215
    01362011200
    01362022330
    0157202XXXXXX
    017620020231216
    01362010800
    01362021930
    0157202XXXXXX
    017620020231218
    01362010800
    01362020900
    0157202XXXXXX
    017620020231218
    01362011200
    01362022330
    0157202XXXXXX
    017620020231219
    01362010800
    01362021000
    0157202XXXXXX
    017620020231219
    01362011000
    01362021200
    0147201IGEL,
    0247202PRP + OD + ESTW
    017620020231219
    01362011200
    01362021400
    0157202XXXXXX
    017620020231220
    01362010800
    01362021930
    0157202XXXXXX
    017620020231221
    01362010800
    01362021930
    0157202XXXXXX
    017620020231222
    01362010800
    01362020900
    0157202XXXXXX
    017620020231222
    01362011200
    01362022330
    0157202XXXXXX
    017620020231223
    01362010800
    01362021930
    0157202XXXXXX
    017620020231225
    01362010800
    01362020900
    0157202XXXXXX
    017620020231225
    01362010900
    01362021200
    0177202Feiertag
    017620020231225
    01362011200
    01362022330
    0157202XXXXXX
    017620020231226
    01362010800
    01362021000
    0157202XXXXXX
    017620020231226
    01362011000
    01362021200
    0177202Feiertag
    017620020231226
    01362011200
    01362021400
    0157202XXXXXX
    017620020231226
    01362011400
    01362021730
    0177202Feiertag
    017620020231227
    01362010800
    01362021930
    0157202XXXXXX
    017620020231228
    01362010800
    01362021930
    0157202XXXXXX
    017620020231229
    01362010800
    01362020900
    0157202XXXXXX
    017620020231229
    01362010900
    01362021200
    0157202Urlaub
    017620020231229
    01362011200
    01362022330
    0157202XXXXXX
    017620020231230
    01362010800
    01362021930
    0157202XXXXXX
    017620020231205
    01362011000
    01362021200
    0147201IGEL,
    0247202PRP + OD + ESTW
    0157202XXXXXX

    017620020231205
    01362011200
    01362021400
    0157202XXXXXX

    017620020231206
    01362010800
    01362021930
    0157202XXXXXX

    Das wäre der Vergleich. Die 3 Blöcke würden fehlen... Ich bekomm den Marker jedoch einfach nicht gesetzt.
    Das Laden der Textdatei dauert auch 15 Minuten, wenn ich bedenke das ich 2 Dateien laden muss, bin ich 30 Minuten mit Kaffee trinken beschäftig :D
    Jemand eine Idee wie es schneller gehen könnte?
    Nein! Doch! OHH!

    samson schrieb:

    Der Hersteller des Konverters hat nachgebessert
    Da wurden Medizin-Daten upgedatet ohne eine Sicherungs-Kopie gemacht zu haben :?: :?: :?:
    Eigentlich ist doch diese Arbeit die Arbeit des Konverter-Schreibers, da der nun genau wissen sollte, wie die Daten "verschwunden" sind.
    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!
    Da hab ich gestern Abend kräftig auf dem Schlauch gestanden :S . Mein Ansatz wäre zwar die Datensatzblockbildung pro Datei, aber das ist ja erst der erste Schritt. Danach wär natürlich nötig zu vergleichen, welchen Datensatzblöcke in beiden Dateien vorhanden sind und welche fehlen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    wie gesagt: Man muss Datensätze bilden, und mindestens von der unvollständigen Datei müssen auch alle Datensätze in ein HashSet. Muss man probieren, ich glaub aber, heutige Rechner kommen auch mit solchen Mengen klar.
    Die vollständige Datei kann man auch mit einem StreamReader Datensatz für Datensatz einlesen, und gucken, ob er im Hashset vorhanden ist - Wenn nicht -> Ausgabe in ExtraDatei.


    Interessehalber: Kriegst du so eine Datei nach Notepad++ geladen?
    Ich habs noch nicht geschafft, np++ mit einer RiesenDatei zu schreddern.
    Für wirklich große Dateien würde ich Sublime Text vorschlagen. Der Start des Programms dauert gefühlt etwas und auch während RegEx-Operationen fühlt es sich gemächlich an. Aber auch die Stabilität des Programms ist unerschütterlich.
    Man kann auch ohne Kauf benutzen: sublimetext.com/download_thanks?target=win-x64
    Ich hab mal ein RecordFinder gemacht, der mit den gegebenen SampleDaten korrekt arbeitet:

    VB.NET-Quellcode

    1. Imports System.IO
    2. Public Module modMain
    3. Public Sub Main(args As String())
    4. Dim hshUnvollst = New HashSet(Of String)(ReadFileRecords("..\..\Unvollstaendig.txt"))
    5. Using wr = New StreamWriter("..\..\Ergaenzung.txt")
    6. For Each record In ReadFileRecords("..\..\Vollstaendig.txt")
    7. If Not hshUnvollst.Contains(record) Then wr.WriteLine(record)
    8. Next
    9. End Using
    10. End Sub
    11. Private Iterator Function ReadFileRecords(pth As String) As IEnumerable(Of String)
    12. Dim record As New List(Of String)
    13. Using rd = New StreamReader(pth)
    14. Do
    15. Dim line = rd.ReadLine()
    16. If line Is Nothing Then Return
    17. record.Add(line)
    18. If line.Substring(3, 4) = "7202" Then
    19. Yield String.Join(CrLf, record) ' return die mehreren Zeilen des records zu einem String verschmolzen
    20. record.Clear()
    21. End If
    22. Loop
    23. End Using
    24. End Function
    25. End Module

    Wäre interessant, bis wie grosse Files der verarbeiten kann. Evtl. kann man die Leistung verzehnfachen, wenn man die Records komprimiert um Faktor 10, aber die sind eiglich eh nicht besonders gross.
    Dateien

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

    @ErfinderDesRades @VaporiZed @Dksksm
    erst einmal vielen Dank für den ganzen Input.
    In der Tat hat der Konverter-Hersteller die Software korrigiert, war seine Aufgabe, hat er gemacht.
    Problem war einfach, die Praxis musste mit den Daten starten und damit wurde die Daten unvollständig importiert.
    Nun haben wir 2 Dateien. Eine wo alle Termine drin sind, das war nach der Nachbesserung des Herstellers und eine die eben unvollständig ist.
    Jetzt hat die Praxis aber schon 2-3 Wochen damit gearbeitet und Termine die bereits gelaufen sind und ggf. in der Zukunft liegen bearbeitet.
    Daher kommt ein Löschen der Daten nicht mehr in Frage, sonst würden wir einfach den kompletten Kalender "leeren". Würde jedoch auch neue Termine entfernen die nicht in den konvertierten Daten sind.

    @ErfinderDesRades
    Vielen herzlichen Dank für deinen Code. Ich hab es auf die Schnelle mal kurz getestet. Er Spuckt mir eine Datei aus mit einer Größe um ca. 1MB
    Es stehen auch viele Sachen drin, ob die korrekt sind, muss ich händisch prüfen.
    Ich gebe dir heute Abend bescheid ;) Muss jetzt los zum Kundentermin :(
    Vielen Vielen Dank!

    PS: Die Laufzeit waren 2 Sekunden ;)

    Grüße Stefan
    Nein! Doch! OHH!

    samson schrieb:

    Daher kommt ein Löschen der Daten nicht mehr in Frage, sonst würden wir einfach den kompletten Kalender "leeren". Würde jedoch auch neue Termine entfernen die nicht in den konvertierten Daten sind.
    Ich würde dann die Sicherungskopie neu konvertieren und die Differenz zur aktuellen Datenbank übernehmen.
    Und danach die Dateien bereinigen.
    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!

    samson schrieb:

    Es stehen auch viele Sachen drin, ob die korrekt sind, muss ich händisch prüfen.
    naja, wenn der erste, zweite und letzte Datensatz korrekt ist, dann gibts eiglich kaum Möglichkeiten, dass noch fehler drin sind.

    Es kann bei so Export-Import-Dateien zu Problemen mit dem Encoding kommen.
    Mein Snippet gibt eine Datei mit utf8 aus.
    Aber wenn du die Ergänzung via Notepad++ oder sowas anhängst, hat np++ ja die Zieldatei geöffnet, und kennt das Encoding (falls es von utf8 abweicht)
    @ErfinderDesRades Danke für den Hinweis.
    Ich hab mir Quell und Zieldatei mal angesehen und festgestellt das die Zeichenkodierung hinüber ist.
    Laut Windows Notepad und Notepad++ ist die Quelldatei eine ANSI Datei.
    Da ich ehrlich gesagt deinen Code nicht ganz verstehe würde ich dich nochmal um Hilfe bitten, das wir die Zeichenkodierung anpassen können :)

    Quellcode

    1. Using wr = New StreamWriter("Ergaenzung.bdt", Text.Encoding.ANSI)

    funktioniert so ja leider nicht.

    Nach etwas Würfeln an der Originaldatei kam heraus, das Ansi nicht gleich Ansi ist.
    Hinter der Datei und dem Umlautproblem versteck sich OEM 852, Mit dieser Codierung findet man auch alle Umlaute wieder.

    Viele Grüße,
    Stefan
    Nein! Doch! OHH!

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