Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Daten aus einem Stream lesen und darstellen (https://www.delphipraxis.net/108711-daten-aus-einem-stream-lesen-und-darstellen.html)

Ares 18. Feb 2008 10:45


Daten aus einem Stream lesen und darstellen
 
Hallo!

Ich will Daten aus einer Datei bzw. einem Stream auslesen und wie in einem Hex-Editor darstellen. Ich scheitere aber daran, dass ich nicht weiß, welchen Datentyp ich für die Variable verwenden soll in die die Daten aus dem Stream gelesen werden. Ich habe folgendes Testprogramm geschrieben:

Delphi-Quellcode:
unit main;

...

function ShowBinary(var Data; Count: Cardinal): TStrings;

implementation

{$R *.dfm}

procedure TForm1.readBtClick(Sender: TObject);
var Stream: TStream;
    Data: array of byte;
begin
  Memo1.Lines.Clear;

  setLength(Data, 128);
  Stream := TFileStream.Create('D:\Test.txt', fmOpenRead or fmShareDenyNone);
  Stream.Seek(0, soFromBeginning);
 
  Stream.Read(Data[0], 128);  // <-- funktioniert, aber falsche Darstellung
  //Stream.Read(Data, 128);     // <-- korrekte Darstellung aber Exception

  Memo1.Lines.AddStrings(ShowBinary(Data, 128));
end;


// ShowBinary stammt von [url]http://www.swissdelphicenter.com/de/showcode.php?id=944[/url]
// Wurde nur leicht modifiziert um TStrings zurück zu geben...
function ShowBinary(var Data; Count: Cardinal): TStrings;
var
  line: string[80];
  i: Cardinal;
  p: PChar;
  nStr: string[4];
const
  posStart = 1;
  binStart = 7;
  ascStart = 57;
  HexChars: PChar = '0123456789ABCDEF';
begin
  result := TStringList.Create;

  p   := @Data;
  line := '';
  for i := 0 to Count - 1 do begin
    if (i mod 16) = 0 then begin
      if Length(line) > 0 then
        result.Add(line);
      FillChar(line, SizeOf(line), ' ');
      line[0] := Chr(72);
      nStr   := Format('%4.4X', [i]);
      Move(nStr[1], line[posStart], Length(nStr));
      line[posStart + 4] := ':';
    end;

    if p[i] >= ' ' then
      line[i mod 16 + ascStart] := p[i]
    else
      line[i mod 16 + ascStart] := '.';

    line[binStart + 3 * (i mod 16)]    := HexChars[(Ord(p[i]) shr 4) and $F];
    line[binStart + 3 * (i mod 16) + 1] := HexChars[Ord(p[i]) and $F];
  end;
  result.Add(line);
end;
Bei einem Klick auf den Read-Button sollen die ersten 128 Bytes einer Textdatei eingelesen und im Hex-Format angezeigt werden. Die Text Datei enhält folgenden Inhalt:
Zitat:

Test Test Test Test Test Test Test Test Test Test
Test Test Test Test Test Test Test Test Test Test
Test Test Test Test Test Test Test Test Test Test
Test Test Test Test Test Test Test Test Test Test
Test Test Test Test Test Test Test Test Test Test
...
Wenn ich nun "Stream.Read(Data[0], 128);" funktioniert alles ohne Fehler, aber es wird folgender Inhalt angezeigt:
Zitat:

0000: B8 86 DA 00 F4 F5 12 00 FA 8F 43 00 70 0E DE 00 ¸†Ú.ôõ..úC.p.Þ.
0010: 4B 83 42 00 50 F6 12 00 49 84 42 00 70 0E DE 00 KƒB.Pö..I„B.p.Þ.
0020: F2 8A 43 00 50 F6 12 00 58 F8 12 00 70 0E DE 00 òŠC.Pö..Xø..p.Þ.
0030: 08 CB A8 00 D2 39 01 7A A5 C3 83 76 16 B9 83 76 .˨.Ò9.z¥Ãƒv.¹ƒv
0040: D2 39 01 7A 3A 00 00 00 10 F5 12 00 20 00 00 00 Ò9.z:....õ.. ...
0050: 08 F5 12 00 86 2D 84 76 0A 80 00 00 94 F5 12 00 .õ..†-„v.€..”õ..
0060: B1 B5 84 76 0A 80 00 00 5A 12 18 00 FC FF FF FF ±µ„v.€..Z...üÿÿÿ
0070: 00 00 00 00 00 00 00 00 30 F6 12 00 CE 22 85 76 ........0ö..Î"…v
Diese Daten sind nicht in der Datei enthalten und kann mir nicht erklären wo diese herkommen...

Verwende ich hingegen "Stream.Read(Data, 128);" wird eine Exception ausgelöst, aber es wird trotzdem der korrekte Inhalt angezeigt:
Zitat:

Im Projekt Project1.exe ist eine Exception der Klasse EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse 004056FC in Modul 'Project1.exe'. Schreiben von Adresse 7473654C' aufgetreten.
Zitat:

0000: 54 65 73 74 20 54 65 73 74 20 54 65 73 74 20 54 Test Test Test T
0010: 65 73 74 20 54 65 73 74 20 54 65 73 74 20 54 65 est Test Test Te
0020: 73 74 20 54 65 73 74 20 54 65 73 74 20 54 65 73 st Test Test Tes
0030: 74 0D 0A 54 65 73 74 20 54 65 73 74 20 54 65 73 t..Test Test Tes
0040: 74 20 54 65 73 74 20 54 65 73 74 20 54 65 73 74 t Test Test Test
0050: 20 54 65 73 74 20 54 65 73 74 20 54 65 73 74 20 Test Test Test
0060: 54 65 73 74 0D 0A 54 65 73 74 20 54 65 73 74 20 Test..Test Test
0070: 54 65 73 74 20 54 65 73 74 20 54 65 73 74 20 54 Test Test Test T
Kann mir jemand sagen, was ich falsch mache? Welchen Datentyp muss ich die Varable Data verwenden und wie muss ich diese mit Stream.Read() nutzen, damit die korrekten Daten ohne Fehler gelesen werden?

Besten Dank
Ares

Nuclear-Ping 18. Feb 2008 12:20

Re: Daten aus einem Stream lesen und darstellen
 
Warum übergibst du nicht den Pointer des Streams? (Hast da übrigens 'n Speicherleck ;))

Delphi-Quellcode:
unit main;

...

function ShowBinary(var Data: Pointer; Count: Cardinal): TStrings;

implementation

{$R *.dfm}

procedure TForm1.readBtClick(Sender: TObject);
var Stream: TFileStream;
begin
  Stream := TFileStream.Create('D:\Test.txt', fmOpenRead or fmShareDenyNone);
  try
    Stream.Seek(0, soFromBeginning);
    Stream.Read(Data[0], 128);
    Stream.Position := 0;
    Memo1.Lines.AddStrings(ShowBinary(Stream.Memory, Stream.Size));
  finally
    FreeAndNil (Stream);
  end;
end;


// ShowBinary stammt von [url]http://www.swissdelphicenter.com/de/showcode.php?id=944[/url]
// Wurde nur leicht modifiziert um TStrings zurück zu geben...
function ShowBinary(var Data: Pointer; Count: Cardinal): TStrings;
var
  line: string[80];
  i: Cardinal;
  p: PChar;
  nStr: string[4];
const
  posStart = 1;
  binStart = 7;
  ascStart = 57;
  HexChars: PChar = '0123456789ABCDEF';
begin
  result := TStringList.Create;

  p   := @Data;
  line := '';
  for i := 0 to Count - 1 do begin
    if (i mod 16) = 0 then begin
      if Length(line) > 0 then
        result.Add(line);
      FillChar(line, SizeOf(line), ' ');
      line[0] := Chr(72);
      nStr   := Format('%4.4X', [i]);
      Move(nStr[1], line[posStart], Length(nStr));
      line[posStart + 4] := ':';
    end;

    if p[i] >= ' ' then
      line[i mod 16 + ascStart] := p[i]
    else
      line[i mod 16 + ascStart] := '.';

    line[binStart + 3 * (i mod 16)]    := HexChars[(Ord(p[i]) shr 4) and $F];
    line[binStart + 3 * (i mod 16) + 1] := HexChars[Ord(p[i]) and $F];
  end;
  result.Add(line);
end;

jottkaerr 18. Feb 2008 12:23

Re: Daten aus einem Stream lesen und darstellen
 
Hallo,

Dein Aufruf von ShowBinary() ist falsch. Auch dort musst Du Data[0] als ersten Parameter übergeben. Das erklärt auch, wieso die zweite, eigentlich falsche Variante des Aufrufs von Stream.Read() zuerst zu funktionieren scheint: Du überschreibst hier den Bereich, an dem Deine lokalen Variablen (und die Rücksprungadresse) liegen, und liest diesen Bereich in ShowBinary() wieder aus. Beim Verlassen von readBtClick() scheppert's dann.

jkr

Ares 18. Feb 2008 12:33

Re: Daten aus einem Stream lesen und darstellen
 
Zitat:

Zitat von jottkaerr
Hallo,

Dein Aufruf von ShowBinary() ist falsch. Auch dort musst Du Data[0] als ersten Parameter übergeben.

Vielen Dank für den Hinweis! Jetzt funktioniert es prima!

Muetze1 18. Feb 2008 18:01

Re: Daten aus einem Stream lesen und darstellen
 
@Nuclear-Ping: Dein Code klappt so auch nicht, da du eine Property nicht als Var Parameter angeben kannst.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:09 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