Autor |
Beitrag |
Masterrandy
      
Beiträge: 55
|
Verfasst: 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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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 
      
Beiträge: 55
|
Verfasst: 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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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 
      
Beiträge: 55
|
Verfasst: 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
Quelltext
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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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.
|
 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 
      
Beiträge: 55
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mi 09.04.03 14:06
Hallo!
Hier ein einfacher Stream-Gebrauch:
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 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 UGrohne: Code- durch Delphi-Tags ersetzt.
|
|
maximus
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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 
      
Beiträge: 55
|
Verfasst: Mi 09.04.03 14:42
Titel: Meine Datenstruktur
Ich habe folgende Datenstruktur:
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 UGrohne: Code- durch Delphi-Tags ersetzt.
|
|
maximus
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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
Wie man mit nem FileStream umgeht ist ja oben beschrieben und deine records kannst alla for 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
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 
      
Beiträge: 55
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mi 09.04.03 15:47
Ja aber wieso das denn??? (  ) 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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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: Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| fileStream.writeInteger(length(arrDings)); for i := 0 to length(arrDings)-1 do begin fileStream.writeString(ArrDings[i].name); fileStream.loadFromStream(ArrDings[i].memoryStream); end; |
oder?
PS: ähm...writeString, writeInteger gibt es natürlich nicht  Hab hab mich da wieder von TWriter und TReader anstecken lassen
Moderiert von UGrohne: Code- durch Delphi-Tags ersetzt.
_________________ mfg.
mâximôv
|
|
Masterrandy 
      
Beiträge: 55
|
Verfasst: 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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Do 10.04.03 13:44
Nimm zum Speichern und Lesen von Strings einfach diese Routinen:
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
      
Beiträge: 896
Win XP, Suse 8.1
Delphi 4/7/8 alles prof
|
Verfasst: 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 
_________________ mfg.
mâximôv
|
|
Masterrandy 
      
Beiträge: 55
|
Verfasst: 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.
|
|