AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Stringlänge setzen, dann füllen

Ein Thema von Luckie · begonnen am 10. Jun 2004 · letzter Beitrag vom 10. Jun 2004
Antwort Antwort
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 00:00
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:
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;
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?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Brüggendiek

Registriert seit: 13. Dez 2002
Ort: Dortmund
275 Beiträge
 
Delphi 5 Standard
 
#2

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 02:11
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
foo := foo + IntToHex(dummy, 8) + ' '; die Werte nicht in den String, sondern dahinter!

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:
neu := IntToHex(dummy, 8) + ' ';
for position := 1 to 8 do
  foo [i * 8 + position] := neu [position];
(Dir brauche ich die Variablentypen ja nicht zu erklären, oder?)

oder durch direktes Speicherkopieren:
Delphi-Quellcode:
neu := IntToHex(dummy, 8) + ' ';
Move (neu [1], foo [i * 8 + 1], 8);
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.

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!

Gruß

Dietmar Brüggendiek
Dietmar Brüggendiek
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 02:47
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:
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;
Braucht halt nur noch ne Schleife, oder aber man könnte was mit Move machen. Das weiss ich aber nicht wirklich
(Ist zu dem ungetestet! Wenn das Quark war, dann seht's mir nach... jaja, das gute Pils)


gruss,
dizzy
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Vjay

Registriert seit: 2. Dez 2003
Ort: Berlin/Eschede
481 Beiträge
 
Delphi 7 Professional
 
#4

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 09:15
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.
Wer später bremst ist eher tot.
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 10:03
Zitat von Brüggendiek:
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.
Das war Sinn und Zweck der Übung.

Zitat:
Allerdings kopierst Du dann mit
foo := foo + IntToHex(dummy, 8) + ' '; die Werte nicht in den String, sondern dahinter!
Ja, als ich nachts aufgewacht bin, ist es mir auch klar geworden.

Zitat:
Du mußt schon den Wert ab der richtigen Position in den String kopieren!
Ähm, ja. Es war schon spät.

Zitat:
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!
War kein Test. Hatte einen Blackout.

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:
Move (neu [1], foo [i * 8 + 1], [b]8[/b]);
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], length(neu)); 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.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Brüggendiek

Registriert seit: 13. Dez 2002
Ort: Dortmund
275 Beiträge
 
Delphi 5 Standard
 
#6

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 10:43
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
Dietmar Brüggendiek
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#7

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 10:56
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;
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Basilikum

Registriert seit: 9. Aug 2003
389 Beiträge
 
Delphi 7 Professional
 
#8

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 12:14
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:
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;
eine noch optimalere Variante wäre diese:

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;
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#9

Re: Stringlänge setzen, dann füllen

  Alt 10. Jun 2004, 12:27
Zitat von Basilikum:
hm... wesshalb verwendest du für 1 Byte 8 Hex-Stellen ?
Keine Ahnung, habe ich eben nur mal so schnell festgelegt. Aber darauf kommt es nicht an.

Zitat:
weiter kann man sich das foo sparen, und direkt Result verwenden.... also:
Könnte man. Aber mit der Hilfsvaraible kann der Compiler besser optimieren. Siehe hier: http://www.delphipraxis.net/internal...?p=93878#93878
Zitat von Hagen:
Delphi-Quellcode:
function BadResultUsage: Integer;
var
  I: Integer;
begin
  Result := 1;
  for I := 0 to 1024 do
    Result := Result + Result;
end;

function GoodUsage: Integer;
var
  I,J: Integer;
begin
  J := 1;
  for I := 0 to 1024 do
    J := J + J;
  Result := J;
end;
In komplexeren Sources wird nämlich in BadResultUsage das Resultat im Stack zwischen gespeichert. In GoodUsage geben wir aber dem Optimierer in J die Berechnungsvariable vor, die der Optimierer innerhalb der Loop in ein Register optimieren kann. Erst am Ende der Funktion wird das Resultat belegt, was meistens durch den Optimierer einfach bedeutet das er das optimierte Register J ind Register EAX kopiert. In BadResultUsage wäre dies aber im Stack gespeichert.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:43 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz