![]() |
Stringlänge setzen, dann füllen
Erst mal der Code:
Delphi-Quellcode:
type
TMyByteArray = array of byte; function BuffToHex(ByteArray: TMyByteArray): string; var i: Integer; dummy: Integer; foo: string; begin Setlength(foo, length(ByteArray) * 9); for i := 0 to length(ByteArray) - 1 do begin dummy := ord(ByteArray[i]); foo := foo + IntToHex(dummy, 8) + ' '; end; result := foo; end;
Delphi-Quellcode:
Unter Prozedur liest 100 Bytes einer Datei ein. Die Funktion BufToHex wandelt das ganze in eine hexadezimale Darstellung um. So mein Problem: Eigentlich wollte ich für den String vorher Speicher reservieren / ihn auf die erforderliche Länge setzten und ihn dann füllen. Tue ich das wie oben im Code, steht am Anfang vom String nur Mist und am Ende dann die umgewandelten Byte-Werte. Wo ist mein Denkfehler? Oder was mache ich falsch?
procedure TForm1.Button1Click(Sender: TObject);
var fs: TFileStream; Buffer: TMyByteArray; begin Setlength(Buffer, 100); fs := TFileStream.Create('G:\MP3s\Beatles\Beatles - Blue Jay Way.mp3', fmOpenRead); try fs.ReadBuffer(Buffer[0], 100); Memo1.Text := BuffToHex(Buffer); finally FreeAndNil(fs); end; end; |
Re: Stringlänge setzen, dann füllen
Hallo Luckie!
Du setzt den String am Anfang auf die richtige Länge. Soweit, so gut - ist auch zu empfehlen, da das ständige Verlängern des Strings (dynamisches Array) ja den Speicher vollmüllt. Allerdings kopierst Du dann mit
Delphi-Quellcode:
die Werte nicht in den String, sondern dahinter!
foo := foo + IntToHex(dummy, 8) + ' ';
In Pascal ist das nicht so möglich, wie Du willst - in SIMULA ging das, weil es da eine String-Position gibt. Du mußt schon den Wert ab der richtigen Position in den String kopieren! Entweder mit einer Schleife:
Delphi-Quellcode:
(Dir brauche ich die Variablentypen ja nicht zu erklären, oder?)
neu := IntToHex(dummy, 8) + ' ';
for position := 1 to 8 do foo [i * 8 + position] := neu [position]; oder durch direktes Speicherkopieren:
Delphi-Quellcode:
Das in dem String ansonsten Müll steht, ist logisch: das SetLength setzt nur die Länge, initialisiert das Ganze aber nicht. Eventuell sollte also auf SetLength noch ein FillChar folgen - ist abe hier unnötig, da die Programmlogik den reservierten Bereich vollständig füllt.
neu := IntToHex(dummy, 8) + ' ';
Move (neu [1], foo [i * 8 + 1], 8); Allerdings habe ich mit Deiner Frage ein kleines Problem: Willst Du uns testen - oder warst Du beim Proggen nicht gerade gut drauf? Von Dir hätte ich sonst so eine Frage nicht erwartet! :stupid: Gruß Dietmar Brüggendiek |
Re: Stringlänge setzen, dann füllen
Auch ohne den theoretischen Hintergrund hätte ich auf einen indizierten Zugriff auf "foo" gewettet.
Es würde schon reichen es so zu machen:
Delphi-Quellcode:
Braucht halt nur noch ne Schleife, oder aber man könnte was mit Move machen. Das weiss ich aber nicht wirklich ;)
var k: Integer;
dummy: String; // jaja, ein String... :) begin Setlength(foo, length(ByteArray) * 9); i := 0; while i < length(ByteArray) - 1 do begin dummy := IntToHex(ord(ByteArray[i]), 8); for k := 0 to 7 do foo[i+k] := dummy[k]; foo[i+8] := ' '; inc(i, 9); end; result := foo; end; (Ist zu dem ungetestet! Wenn das Quark war, dann seht's mir nach... jaja, das gute Pils) gruss, dizzy |
Re: Stringlänge setzen, dann füllen
Move verwenden, weil wenn du Char für char kopierst haste den Geschwindigkeitsvorteil, den du erreichen willst, gleich wieder verspielt.
Wenn man die Stringlänge mehrmals ändert müllt man nicht den Speicher zu, weil der komplette String kopiert wird > zusammenhängender Speicher. Sonst würde man ja s1[1..9] und dann weiter bei s1[50..63] haben. |
Re: Stringlänge setzen, dann füllen
Zitat:
Zitat:
Zitat:
Zitat:
So. Ich habe mich jetzt für Move entschieden, nur gibt es da ein kleines Problem: Die Leerzeichen fehlen, die ich dranhänge, um die Bytes zu trennen. Erst dachte ich logisch, Brüggendiek hat sich vertan:
Code:
neu ist aber natürlich nicht 8 Zeichen lang, sondern 9 (8 Hex-Stellen plus Leerzeichen). Als ich die dann Zeile dann auf
Move (neu [1], foo [i * 8 + 1], [b]8[/b]);
Delphi-Quellcode:
geändert habe, fehlten sie aber trotzdem noch. Wenn ich mir jetzt den Index ankucke: i*8+1, dann ist der Index beim ersten Schleifendurchlauf 1, beim zweiten 9 und damit überschreibt er das Leerzeichen. Danke für das zuhören, habe gerade durch das Selbstgespräch die Lösung gefunden: Es muss heißen: i*9+1. ;)
Move (neu [1], foo [i * 8 + 1], length(neu));
|
Re: Stringlänge setzen, dann füllen
Hallo Luckie!
Sorry mit dem Leerzeichen - die 9 hatte ich in Deinem Eingangspost genausowenig wie das Leerzeichen nach der Umwandlung gar nicht gesehen (und dann auch noch per Copy&Paste in mein Posting gesetzt). Der Fehler war allerdings derart "ins Auge springend", daß ich mir den Rest nicht sehr intensiv angesehen hatte - zumal das Prinzip ja stimmte. Wegen dieser Offensichtlichkeit hatte ich ja auch meine abschließende Frage gestellt. Gruß Dietmar Brüggendiek |
Re: Stringlänge setzen, dann füllen
So, jetzt habe ich das Programm fertig. Es ging mir eigentlich nur darum eine binäre Datei einzulesen und darzustellen. Ich poste es einfach mal, die Frage kommt ja immer wieder, wie man eine Datei binär einliest. Es macht eigentlich nichts sinnvolles, aber eventuell kann es ja jemand mal brauchen.
Delphi-Quellcode:
type
TMyByteArray = array of byte; function BuffToHex(ByteArray: TMyByteArray): string; var i: Integer; s: String; foo: string; begin Setlength(foo, length(ByteArray) * 10); for i := 0 to length(ByteArray) - 1 do begin s := '$'+IntToHex(ord(ByteArray[i]), 8) + ' '; Move(s[1], foo[i * 10 + 1], length(s)); end; result := foo; end; procedure TForm1.Button1Click(Sender: TObject); var fs: TFileStream; Buffer: TMyByteArray; BytesRead: Longint; s: String; i: Int64; begin i := 0; SetLength(Buffer, 100); fs := TFileStream.Create('G:\MP3s\Beatles\Beatles - Blue Jay Way.mp3', fmOpenRead); SetLength(s, fs.size*10); Progressbar1.Max := fs.Size div 100; try repeat BytesRead := fs.Read(Buffer[0], 100); Move(BuffToHex(Buffer)[1], s[i*10+1], 10); Inc(i); Progressbar1.StepIt; Application.ProcessMessages; until BytesRead < 100; Memo1.Text := s; finally FreeAndNil(fs); end; end; |
Re: Stringlänge setzen, dann füllen
hm... wesshalb verwendest du für 1 Byte 8 Hex-Stellen ? jede Hex-Stelle entspricht 1 Nibble = 4 Bit, sprich: für ein Byte würden 2 Stellen ausreichen... die restlichen 6 werden mit Garantie nie ungleich 0 sein.... weiter kann man sich das foo sparen, und direkt Result verwenden.... also:
Delphi-Quellcode:
eine noch optimalere Variante wäre diese:
function BuffToHex(ByteArray: TMyByteArray): string;
var i: Integer; s: String; begin Setlength(Result, length(ByteArray) * 4); for i := 0 to length(ByteArray) - 1 do begin s := '$' + IntToHex(ord(ByteArray[i]), 2) + ' '; Move(s[1], result[i * 4 + 1], length(s)); end; end;
Delphi-Quellcode:
function BuffToHex(ByteArray: TMyByteArray): string;
const HexDigits : array[$0..$f] of char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); var i : integer; begin Setlength(Result, length(ByteArray) * 4); for i := 0 to length(ByteArray) - 1 do begin result[i * 4 + 1]:='$'; result[i * 4 + 2]:=HexDigits[ByteArray[i] shr 4]; result[i * 4 + 3]:=HexDigits[ByteArray[i] and $f]; result[i * 4 + 4]:=' '; end; end; |
Re: Stringlänge setzen, dann füllen
Zitat:
Zitat:
![]() Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:36 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz