PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Delphi: Auf Daten binär zugreifen?


aths
2004-09-27, 15:56:46
Ich möchte einen Single (FP32) binär erstellen. Geht das direkt? Könnte man zur Not als Umweg einen Integer erstellen und die Daten binär als Single interpretieren lassen? Ein Variant zu casten dürfte nicht sonderlich performant sein.

eXistence
2004-09-27, 16:10:19
Was genau hast du denn vor?
Du kannst Werte (fast) beliebigen Typs in einen (file-)Stream schreiben. Dem ist ziemlich egal was da kommt, er schreibt stur ein byte nach dem anderen und verlässt sich darauf, das der Programmierer weiß was er da tut :)
Dein single wäre auf diese Art binär gespeichert und kann auch problemlos wieder ausgelesen werden (auch von anderen Programmen, ggf. muss man die byte-Reihenfolge aber umdrehen...).

aths
2004-09-27, 16:14:25
Was genau hast du denn vor?
Du kannst Werte (fast) beliebigen Typs in einen (file-)Stream schreiben. Dem ist ziemlich egal was da kommt, er schreibt stur ein byte nach dem anderen und verlässt sich darauf, das der Programmierer weiß was er da tut :)
Dein single wäre auf diese Art binär gespeichert und kann auch problemlos wieder ausgelesen werden (auch von anderen Programmen, ggf. muss man die byte-Reihenfolge aber umdrehen...).Massenhafte Konvertiertung wäre erst der zweite Schritt. Zunächst müsste ich eine Test-Funktion schreiben, die ein Single zurückliefert.

Allerdings: Wie interpretiert man Elemente aus einem TMemoryStream als Single?

eXistence
2004-09-27, 16:22:47
Indem du die korrekte anzahl an bytes in die entsprechende var liest.
Hier ist ne Funktion, die ich vor längerem geschrieben habe, die mir aus einem Stream ein single herausliest:

function TForm1.GetSingle(scrStream : TStream; iPos : integer) : double;
var dSingle : Single;
dDouble : Double;
byte0, byte1, byte2, byte3 : byte;

begin
mStream := TMemoryStream.Create;

scrStream.seek(iPos, soFromBeginning);
scrStream.readbuffer(byte0, 1);

scrStream.seek(iPos+1, soFromBeginning);
scrStream.readbuffer(byte1, 1);

scrStream.seek(iPos+2, soFromBeginning);
scrStream.readbuffer(byte2, 1);

scrStream.seek(iPos+3, soFromBeginning);
scrStream.readbuffer(byte3, 1);


mStream.seek(0, SoFromBeginning);
mStream.Write(byte3, SizeOf(byte3));
mStream.Write(byte2, SizeOf(byte2));
mStream.Write(byte1, SizeOf(byte1));
mStream.Write(byte0, SizeOf(byte0));

mStream.seek(0, SoFromBeginning);
mStream.readbuffer(dSingle, 4);
mStream.free;

dDouble := dSingle;
Result := dDouble;

end;

Ist nicht ganz sauber, ich musste die byte-Reiehnfolge umdrehen und gebe das ergebnis als double zurück, aber lass dich davon nicht irretieren :)
Wichtig sit nur das mStream.readbuffer(dSingle, 4);

aths
2004-09-27, 17:20:06
Hm, das sieht mir nicht sehr performant aus. Aber die Idee ist besser als nichts.

Gast
2004-09-27, 17:45:28
ich weiß ja nicht was du vorhast und wie kritisch das ist, aber wenn die Datei nicht allzu groß ist, kannst du sie komplett in einen memory-Stream laden und von dort gehen die Zugriffe relativ flott...

Jazz
2004-09-28, 19:34:05
var
buf : array[0...3] of Byte;
sp : ^Single;
begin
//Buffer füllen, z.B. durch Auslesen einer Datei
sp:=Addr(buf[0]);
Label1.Caption:=FloattoStr(sp^);
end;

Gruß,
Jazz

aths
2004-09-28, 20:43:41
var
buf : array[0...3] of Byte;
sp : ^Single;
begin
//Buffer füllen, z.B. durch Auslesen einer Datei
sp:=Addr(buf[0]);
Label1.Caption:=FloattoStr(sp^);
end;

Gruß,
JazzHm, ich hab das umständlich so gemacht:
v.Seek(0,soFromBeginning);
v.write(s,4);
v.Seek(0,soFromBeginning);
v.read(result,4);Das mit dem Pointer scheint mir eleganter zu sein. Da kann man sich auch sparen, einen TMemoryStream anzulegen.