Hexadecimal Editor for large files

  • VB.NET
  • .NET (FX) 4.5–4.8

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

    Hexadecimal Editor for large files

    Hi,

    heute habe ich ein Problem, wo ich gern euren Rat für ein Design Problem einholen möchte.

    Ich habe einen kleinen HexEditor geschrieben. Mit dem kann man Files hexadezimal anzeigen, nach Text suchen und ggfs. den Text überschreiben oder ersetzen. (s. Anhang)

    Die Anzeige beruht auf einer DataGridView ... der File wird zu Beginn komplett in einen Byte Array eingelesen und dann in die DataGridView eingestellt.

    Die Sache funktioniert sehr gut ...

    ... aber bei großen File (z.B. 1.5 MB dauert die Sache endlos lang (z.B eine halbe Minute).

    Das Einlesen in den ByteArray geht Ratz Fatz (unter 1 Sekunde):

    VB.NET-Quellcode

    1. FileByteArray = File.ReadAllBytes(HexDumpObject)


    Aber die Aufbereitung ist Käse!

    VB.NET-Quellcode

    1. Dim HexData(15) As String
    2. Dim ChrData(15) As String
    3. Dim i As Integer = -1 'Row index
    4. Dim j As Integer = -1 'Column index
    5. Dim myAddr As Integer = 0
    6. For n As Integer = 0 To FileByteArray.Count - 1 'Process all bytes
    7. Dim myByte As Byte = FileByteArray(n)
    8. If j = -1 Then 'Start new row
    9. i += 1 'Increment row pointer
    10. For k = 0 To 15 'Initialize data
    11. HexData(k) = ""
    12. ChrData(k) = ""
    13. Next
    14. End If
    15. j += 1 'Point to next column
    16. 'Convert Byte to Hex ---------------------------------------------------------------------------------------
    17. HexData(j) = myByte.ToString("x2").ToUpper 'Fill hex column
    18. 'Convert Byte to Char --------------------------------------------------------------------------------------
    19. Dim myChar As String = Convert.ToChar(myByte) 'Convert Byte to character
    20. If myByte <= 31 Then myChar = "." '0x00 - 0x1F not displayable
    21. If 128 <= myByte AndAlso myByte <= 160 Then myChar = "." '0x80 - 0xA0 not displayable
    22. ChrData(j) = myChar 'Fill char column
    23. If j = 15 OrElse n = FileByteArray.Count - 1 Then 'Line complete
    24. dgvHexDump.Rows.Add(i.ToString.PadLeft(6, "0"c) & ":", 'Offset and hex address
    25. "0X" & myAddr.ToString("x2").ToUpper.PadLeft(6, "0"c) & ":",
    26. HexData(0), HexData(1), HexData(2), HexData(3), HexData(4), HexData(5), HexData(6), HexData(7),
    27. "",
    28. HexData(8), HexData(9), HexData(10), HexData(11), HexData(12), HexData(13), HexData(14), HexData(15),
    29. "",
    30. ChrData(0), ChrData(1), ChrData(2), ChrData(3), ChrData(4), ChrData(5), ChrData(6), ChrData(7),
    31. ChrData(8), ChrData(9), ChrData(10), ChrData(11), ChrData(12), ChrData(13), ChrData(14), ChrData(15))
    32. j = -1 'Reset column pointer
    33. myAddr += 16 'Increment address
    34. End If
    35. Next


    Ich vermute mal, dass es nicht sehr effizient ist, die Zeilen mit .Add einzustellen.

    Gibt es möglichweise andere Techniken, mit denen man die DataGridView schneller aufbaut.

    Für eure wohlmeinenden Ratschläge bin ich wie immer dankbar ... :)

    LG
    Peter
    Bilder
    • s 2018-09-28 14-27-074.jpg

      56,41 kB, 925×269, 62 mal angesehen

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

    @Peter329 Du musst während der Befüllung die Update-Maschinerie des DGV ausschalten:

    VB.NET-Quellcode

    1. CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).BeginInit()
    2. Me.SuspendLayout()
    3. ' hier das DGV befüllen
    4. CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).EndInit()
    5. Me.ResumeLayout(False)
    Die Vorlage findest Du in der FormX.Designer.vb, wenn Du in der Form ein DGV hast.
    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!
    Danke ! Das sieht jetzt schon deutlich besser aus.

    Für einen File mit 1.5 MB hab ich folgende Zeiten gemessen:

    ReadAllBytes: 0 secs
    BuildDisplay: 9 secs

    Vorher waren es 16 secs ... Damit kann ich zwar schon eher leben. Aber so richtig happy bin ich damit noch nicht.

    Ich hoffe, es gibt noch weitere Verbesserungen ... würde denn Data Binding möglicherweise weiter helfen ?

    LG
    Peter

    Peter329 schrieb:

    Data Binding
    Wie stellst Du denn die Werte dar?
    Wäre die Verwendung einer MultiLine-TextBox eine alte Naive?
    Du musst doch nicht alle Daten vorhalten, sondern nur so viele, wie angezeigt werden.
    Wenn der User PgUp oder PgDown macht, holst Du vom neuen Startpunkt die nächste Portion Bytes.
    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!

    RodFromGermany schrieb:


    Du musst doch nicht alle Daten vorhalten, sondern nur so viele, wie angezeigt werden.
    Wenn der User PgUp oder PgDown macht, holst Du vom neuen Startpunkt die nächste Portion Bytes.


    Für die Anzeige ja ... aber ich will ja auch Suchen und Ersetzen ... dazu muss ich alle Daten verfügbar haben. Funkionen wie "Locate" würden sonst eine recht komplexe Logik erfordern ... ?

    Peter329 schrieb:

    Suchen und Ersetzen
    kann doch auf den Bytes erfolgen.
    Wenn Du alle Bytes vorrätig hast, musst Du lediglich die Anzeige updaten, z.B. 128 Bytes (jedenfalls 2 ^ n) vor bis n Bytes nach dem Treffer oder so, da hast Du ebenfalls fast keinen DGV-Traffic.
    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!
    ok ... auf dem ByteArray kann ich natürlich arbeiten ... da müsste ich halt die Logik zum Suchen und Ersetzen ändern. Das sollte machbar sein.

    Und dann müsste ich halt immer wenn sich die ZeilenSelection ändert, dafür sorgen, dass genügend Zeilen vor und nach der ausgewählten Zeile in der DataGridView angezeigt werden und das Ganze richtig positionieren.

    Das ist natürlich ein gewisser Aufwand ... und so da müsste ich im Detail mich damit befassen:

    was ist, wenn ich mit PageDown in schneller Folge nach unten blättere - da muss das System ja Schritt halten

    wie ist das mit dem Schieberegler ... da stimmt dann die Positionsangabe nicht mehr ... ! Und außerdem ist das die Frage wie das System damit Schritt halten kann. Möglicherweise muss man die ganze Steuerung überdenken.

    Na, es gibt schon einiges zu überdenken. Aber damit hätte ich eben nur eine kleine DGV zum Anzeigen der Daten und führend wäre der ByteArray ... Na, das werd ich mal in Angriff nehmen ! Mal sehen, was daraus wird.

    Vielen Dank und LG
    Peter

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

    @Peter329 Arbeiten mit Daten und deren Anzeige im DGV.
    PgUp/Down, Scroll usw. definieren eine Position im Byte-Array, sei dies der Start der darzustellenden Daten.
    Gib nen Index in eine Darstell-Prozedur, die dann das DGV befüllt.
    Nutze ggf. das DGV nur zur Anzeige, nicht zum Editieren.
    Editieren kannst Du in nem Dialog, der eine Zeile oder so anzeigt, dort könntest Du zeilenweise hoch- und runterschieben.
    Vielleicht mit n TextBoxen, die nur die Hex-Zeichen zulassen.
    Übernehmen und weiter im Text.
    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!
    Jau ... ich habe die Sache jetzt umgestellt. Führend ist nicht mehr die DataGridView sondern der ByteArray mit den Daten. Und ich zeige nur noch die Daten an, die gerade im aktuellen Fenster benötigt werden.

    Das war der Schlüssel zum Erfolg. Vorher hat der Edit einer Datei von 1 MB eine Ladezeit von 20 - 30 Sekunden. Jetzt kann ich eine Datei mit bis zu 2 GB unter einer Sekunde aufrufen !

    Danke für deinen richtungsweisenden Hinweis. Das ist ja immer gut, wenn man weiß in welche Richtung man sich zu bewegen hat. Die Einzelheiten findest du im Thread "Scroll Bar Handling" ... denn die Umsetzung war nicht unbedingt trivial ... :)

    Ganz herzlichen Dank und LG
    Peter
    @Peter329 Welches Control verwendest Du nun zur Anzeige?
    Mir kam die Idee, das DGV abzulösen durch eine RTB, ggf. ReadOnly, wenn bei dieser die Zuordnung Mausklick zu Byte eineindeutig ist.
    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!