Autor Beitrag
Masterrandy
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Di 08.04.03 16:22 
Wie kann ich einen MemoryStream mit blockwrite speichern?
Ich habe im MemoryStream formatierten Text aus einem RichEdit-Feld und die Formatierung soll natürlich erhalten bleiben.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Di 08.04.03 16:27 
Was spricht gegen MemoryStream.saveToFile('c:\muku.rofl');
?

Bei'n bischen text braucht man doch kein blockwrite. oder doch?

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Di 08.04.03 17:20 
Titel: Was dagegen spricht:
Was dagegen spricht ist, dass ich meine anderen Daten bereits in eine Datei schreibe und den Inhalt des Streams auch darin haben möchte.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 09.04.03 11:28 
Wie wärs wenn du ein FileStream hernimmst, den du im schreibmodus öffnest und die position ans ende setzt...dann mitmemoryStream.saveToStream(FileStream);die daten rannhängst?

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Mi 09.04.03 11:57 
Titel: Mein Ansatz
Also momentan verwende ich BlockWrite, da ich verschiedene Felder und Datentypen in eine Datei schreibe. Unter anderem will ich da auch mehrere TMemoryStreams rein schreiben.
Mit BlockWrite schreibe ich in
ausblenden Quelltext
1:
fileDaten: file;					

Da kann ich mit SaveToStream nicht hin schreiben oder?

Ich habe noch nicht versucht erst alles, bis auf die MemoryTreams, zu schreiben, danach die Datei zu öffnen und einen MemoryStream dran zu hängen.

Meine Lösung bis jetzt, und sie scheint zu funktionieren, ist jedes Zeichen aus dem MemoryStream in ein Char mit ReadBuffer zu lesen und dann Stück für Stück dran zu hängen.
Jetzt bin ich gerade am Testen ob das auch immer funktioniert. Falls nicht werde ich auch deinen Vorschlag nochmal testen.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 09.04.03 13:36 
Zitat:
ist jedes Zeichen aus dem MemoryStream in ein Char mit ReadBuffer zu lesen und dann Stück für Stück dran zu hängen.


:D Viel uneffizienter kann mans auch nicht machen. Wenn du byte für byte schreibst, brauchst du auch kein BlockWrite. Dann mach lieben alles via streams, oder versuch auf den buffer der streams zuzugreifen.

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Mi 09.04.03 13:41 
Titel: Beispiel
Kannst du mir da ein Beispiel zeigen wie du das genau meinst?

Zitat:
Viel uneffizienter kann mans auch nicht machen.

Ich weiß, dass es umständlich ist, aber das ist das einzige, dass bis jetzt funktioniert hat.

Zitat:
Wenn du byte für byte schreibst, brauchst du auch kein BlockWrite.

Das blockwrite brauche ich aber, da ich verschiedene Daten in meiner Datei habe und ich auch speichern muss was für ein Block jetzt kommt mit welcher größe (Jedenfalls habe ich das bisher so verstanden).
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mi 09.04.03 14:06 
Hallo!

Hier ein einfacher Stream-Gebrauch:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
var i:integer;
var r:real;
var t:String[50];

procedure LoadFromStream(Stream:TStream);
begin
  Stream.ReadBuffer(i,SizeOf(i));
  Stream.ReadBuffer(r,SizeOf(r));
  Stream.ReadBuffer(t,SizeOf(t));
end;

procedure SaveToStream(Stream:TStream);
begin
  Stream.WriteBuffer(i,SizeOf(i));
  Stream.WriteBuffer(r,SizeOf(r));
  Stream.WriteBuffer(t,SizeOf(t));
end;

procedure DateiSchreiben;
var Stream:TFileStream;
begin
  //Daten speichern
  i:=500;
  r:=1,5;
  t:='Hallo, Welt!';
  Stream:=TFileStream.Create('C:\Testdatei.dat',FmCreate);

  try
    SaveToStream(Stream);
  finally
    Stream.Free;
  end;
end;

procedure DateiLesen;
var Stream:TFileStream;
begin
  Stream:=TFileStream.Create('C:\Testdatei.dat',FmOpenRead);
  try
    LoadFromStream(Stream);
    ShowMessage(IntToStr(i));
    ShowMessage(FormatFloat('0.00',r);
    ShowMessage(t);
  finally
    Stream.Free;
  end;
end;


Wenn du in einem Programm die Routine Dateischreiben aufrufst, werden die Daten durch einen FileStream in eine Datei geschrieben. Rufst du dagegen die Prozedur DateiLesen auf, werden die Variablen aus der Datei gelesen.

Cu,
Udontknow

Moderiert von user profile iconUGrohne: Code- durch Delphi-Tags ersetzt.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 09.04.03 14:06 
Du kannst auch in fileStreams 'blöcke' schreiben:byteCount := FileStream.Write(buffer, BlockLength);

Wär hilfreich wenn du dein file-format beschreiben könntest.

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Mi 09.04.03 14:42 
Titel: Meine Datenstruktur
Ich habe folgende Datenstruktur:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
type 
  TPosition = packed record 
    Datei: Integer; 
    Start: Integer; 
    Definition: Boolean; 
  end

type 
  TAttribute = packed record 
     Name: String
     Typ: Char; 
     Laenge: Integer; 
     Position: array of TPosition; 
  end

type 
  TDaten = packed record 
     Dateiinhalt: TMemoryStream; 
     Dateinamen: String
  end;

Var 
     arrDateien: array of TDaten;
     arrAttribute: array of TAttribute;


Und diese Daten will ich nun alle in eine Datei schreiben.

Bisher bin ich so vorgegangen beim Aufbau der Datei:
    -Version(int)
    -Anzahl Attribute(int)
    +Schleife:
      -Feldtyp (int)
      -Feldgröße(int)
      -Name
      -Feldtyp (int)
      -Feldgröße(int)
      -Feldtyp(int)
      -Wie viel Positionen (int)
      +Schleife für die Daten der Positionen
    -Feldtyp(int) //jetzt für arrDateien
    -Anzahl der Dateien (int)
    +Schleife für die Anzahl
      -Name(string)
      -Dateiinhalt(als MemoryStream vorhanden)


Moderiert von user profile iconUGrohne: Code- durch Delphi-Tags ersetzt.
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 09.04.03 15:22 
Also mit FileStreams hast du natürlich viel luxiriösere möglichkeiten diverse verschiedene typen zu speichern! Ich persöhnlich würde sowas mit den Streams TWriter und TReader machen...das würde jetzt aber zu weit gehn :wink:

Wie man mit nem FileStream umgeht ist ja oben beschrieben und deine records kannst allafor i := 0 to length(arrAttribute)-1 do fileStream.write(arrAttribute[i],sizeOf(TAttribute));abspeichern!

Musst halt mal ein paar testreihen machen, um dich an den umgang mit fileStreams zu gewöhnen :wink:
Mit fileStream.position kannst zB. direkt verschiedene stellen anspringen, falls du daten in die header schreiben musst, die vorher noch nicht feststanden.

erstma viel spass.

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Mi 09.04.03 15:27 
Titel: Und wie funktioniert das mit MemoryStreams?
Und wie funktioniert das mit MemoryStreams?
Dort kann ich dich keine Standardgröße alla SizeOf(TDaten) angeben, da ja nicht vorherbestimmt ist wie groß die Daten im MemoryStream sind.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mi 09.04.03 15:47 
Ja aber wieso das denn??? ( :wink: ) Es ist genau das gleiche wie mit einem Filestream (oder jedem anderen Stream). Wenn du beispielsweise einen Integerwert speicherst, verbrauchst du 4 Byte Platz, sei es jetzt auf einer Festplatte in einer Datei oder im RAM.

Cu,
Udontknow
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Mi 09.04.03 18:26 
Schätze du hast Masterrandy falsch verstanden!

@Masterrandy: Du kannst doch mit memoryStream.size die grösse eines streams bestimmen, den du vorher gefüllt hast?

Edit:

Zitat:
...
-Anzahl der Dateien (int)
+Schleife für die Anzahl

-Name(string)
-Dateiinhalt(als MemoryStream vorhanden)

könnte so aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
fileStream.writeInteger(length(arrDings)); // -Anzahl der Dateien (int)
for i := 0 to length(arrDings)-1 do // +Schleife für die Anzahl 
begin
  fileStream.writeString(ArrDings[i].name); //-Name(string) 
  fileStream.loadFromStream(ArrDings[i].memoryStream); // -Dateiinhalt(als MemoryStream vorhanden)
end;


oder?

PS: ähm...writeString, writeInteger gibt es natürlich nicht :oops: Hab hab mich da wieder von TWriter und TReader anstecken lassen

Moderiert von user profile iconUGrohne: Code- durch Delphi-Tags ersetzt.

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Do 10.04.03 12:01 
Titel: Verwirrt bin
Ich habe jetzt nach dem Beispiel von Udontknow mein Programm umgeschrieben. Ich schreibe auch vor jede Variable die ich da rein schreibe die Größe der Daten. Wenn ich danach die Daten wieder einlese, bekomme ich aber, sobald ich Strings oder den MemoryStream einlese nur Datenmüll geliefert.

Gibt es vllt eine Möglichkeit sich den Inhalt der Datei bitweise anzuschauen? Oder hat jemand eine Ahnung was da schief geht?
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Do 10.04.03 12:19 
Keine ahnung!

Zum debuggen würd ich mir eine log-datei anlegen, wo du exakt protokolierst was du schreibst und liest. Dann kannst du shecken, ob die reihenfolge und grössen stimmen.

Wichtig ist, dass du die memoryStream, vor dem speichern, .position := 0 setzt. Mit den strings kann ich mir vorstellen, das die speicher-reservierung, oder so, nicht korrekt ist -> vielleicht mal nen anderen string-typ nehmen!?

_________________
mfg.
mâximôv
wulfskin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1349
Erhaltene Danke: 1

Win XP
D5 Pers (SSL), D2005 Pro, C, C#
BeitragVerfasst: Do 10.04.03 13:15 
Titel: Re: Verwirrt bin
Masterrandy hat folgendes geschrieben:
Wenn ich danach die Daten wieder einlese, bekomme ich aber, sobald ich Strings oder den MemoryStream einlese nur Datenmüll geliefert. ?
Das liegt daran, des das Programm nicht weiss, wie Groß deine Strings sind. Deshalb kommt er beim Laden ins Schleudern.
Deshalb begrente entweder die Strings auf eine Zeichenanzahl (String[100]), dass ist zwar Platzverbrauchender und einschränkender. geht aber dafür einfacher, oder du schreibst zuerst die Länge und dann den String!

Gruß wulfskin!

_________________
Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Do 10.04.03 13:44 
Nimm zum Speichern und Lesen von Strings einfach diese Routinen:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure SaveStrToStream(const Stream: TStream; const Value: String); 
//Schreibt einen dynamischen String in einen Stream 
var Len: Word; 
begin 
  Len := Length(Value); 
  Stream.WriteBuffer(Len, SizeOf(Len)); 
  if Len > 0 then 
    Stream.WriteBuffer(Pointer(Value)^, Len); 
end; 

procedure LoadStrFromStream(const Stream: TStream; var Str: String); 
//Liest einen dynamischen String aus einem Stream 
var Len: Word; 
begin 
  Stream.ReadBuffer(Len, SizeOf(Len)); 
  SetLength(Str, Len); 
  if Len > 0 then 
    Stream.ReadBuffer(Pointer(Str)^, Len); 
end;


Cu, :)
Udontknow
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Do 10.04.03 13:59 
@UDontknow: "Optimismus ist nur ein Mangel an Information." -> das hat harald schmidt letztens zitiert...das selbe trifft auch auf Pessimismus zu :wink:

_________________
mfg.
mâximôv
Masterrandy Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 55



BeitragVerfasst: Do 10.04.03 14:13 
Titel: Stringlänge steht davor
Ich schreibe ja vor den String die Länge und auch vor den Stream.

Wenn ich den Dateinamen von der gleichen Position, wo ich ihn auch geschrieben habe, in einen String lesen will, kann ich mir den Inhalt auch nicht bei Debug|Evaluate anschauen. Füge ich diesen String in einen Anderen String ein, dann erhalte ich einen Zugriffsfehler.