Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Streams: existierende Daten entfernen / einfügen (https://www.delphipraxis.net/27160-streams-existierende-daten-entfernen-einfuegen.html)

mytar 5. Aug 2004 10:42


Streams: existierende Daten entfernen / einfügen
 
Ich hantiere gerade bei Streams herum.
Nun tauchen bei mir folgende Probleme auf:
  • Wie entferne ich Daten aus einem Stream welcher auf existierende Daten zugreift?
  • Wie füge ich Daten in einen Stream ein, welcher auf existierende Daten zugreift?

mfg
mytar

[edit=sakura] [Klammern entfernt] Mfg, sakura[/edit]

mytar 5. Aug 2004 16:44

Re: [Streams]: existierende Daten entfernen / einfügen
 
Kann mir hier niemand weiterhelfen?

Hier nochmals:

Ich hab eine Datei, und öffne sie via Stream, nun möchte ich mit Seek() die entsprechende Position suchen, und dann was in den Stream einfügen, oder herauslöschen. Die Datei hab ich zuvor selbst erzeugt, ich kenne also die Dateistruktur.


mytar

Luckie 5. Aug 2004 16:50

Re: [Streams]: existierende Daten entfernen / einfügen
 
Wenn du mitten reinschreiben willst, dann wird dir nichts anderes übrigbleiben, als ab der Stelle den Rest in einem memoryStream zwischenzuspeichern, deinen Datensatz reinschreiben und dann den gesicherten Rest wieder dranzuhängen.

mytar 5. Aug 2004 16:53

Re: [Streams]: existierende Daten entfernen / einfügen
 
Danke! Eine gute Lösung, ich bin natürlich nicht draufgekommen!

mytar

F.W. 20. Aug 2004 22:13

Re: [Streams]: existierende Daten entfernen / einfügen
 
Aber wenn ich nach der Position suche und der Stream 4 MB groß ist, dauert das bei mir schon länger, ich glaube ich mach es nicht richtig:

Ich möchte ein Prog schreiben, was ein Bild und text in eine Datei speichert, erst soll es ein paar Memolines in den TFileStream schreiben und dann das Bild. Da der Text des Memos keine Begrenzung haben soll, würde ich beim Datei schreiben einfach ein '[END]' in den Stream schreiben.

Suchen würde ich das Ende des Memos/den Anfang des Bildes mit der folgenden Funktion (hab ich mir ausgedacht, aber sie ist so langsam. Wie sucht man nach einem "Wort" in einem Stream ("professionell")?)

Delphi-Quellcode:
//Aufruf
 Position := GetOffsetOf(FS, '[END]')-1;
 FS.Position

//Funktion
function GetOffsetOf(FS: TFileStream; S: String): Integer;
var
 C: Char;
 B, I: integer;
begin
 I := 0;
 Result := 0;
 While I < FS.Size-1 do begin
     FS.ReadBuffer(C, SizeOf(C));
     Inc(I);
     if UpCase(C) = UpCase(S[1]) then begin
        Result := I;
        for B := 2 to Length(S) do begin
            FS.ReadBuffer(C, SizeOf(C));
            Inc(I);
            if UpCase(C) <> UpCase(S[B]) then begin
               Result := 0;
               Break;
            end;
            if B = Length(S) then Exit;
        end;
     end;
 end;
end;
Also nochmal meine frage: Wie sucht man nach einer Zeichenfolge in einem Stream?

Danke schonmal!

dizzy 20. Aug 2004 22:20

Re: [Streams]: existierende Daten entfernen / einfügen
 
Zitat:

Zitat von F.W.
Also nochmal meine frage: Wie sucht man nach einer Zeichenfolge in einem Stream?

Eine Variante:
Delphi-Quellcode:
var
  str: string[5];
.
.
.
Stream.Read(str, 5);
while str <> 'hallo' do
  Stream.Seek(-4, soFromCurrent);
  Stream.Read(str, 5);
end;
Prinzip: Auf gut Glück einfach nen Block einlesen, und vergleichen. Wenn's nicht passt, dann Blockgröße-1 zurückspringen, und nochmals lesen... usw.usf.
Ist evtl. nicht so performant, aber anders hab ich das bisher auch noch nicht gemacht ;)


gruss,
dizzy

F.W. 20. Aug 2004 22:41

Re: [Streams]: existierende Daten entfernen / einfügen
 
Das ist ja schonmal ein Anfang.

Mir ist gerade was aufgefallen: Wenn ich jedes Zeichen einzeln schreibe (von 'Hallo') wird die Datei 5 Bytes groß und es steht richtig "Hallo" drin (wenn man sie mit HexEditor öffnet). Mach ich es mit
Delphi-Quellcode:
 S := 'Hallo';
 WriteBuffer(S, SizeOf(S));
Dann ist die Datei nurnoch 4 Bytes groß :gruebel: und mit HE kann man Hallo nicht lesen.
Ich habs aber noch nicht geschafft das wieder richtig herzustellen, darum meine (2.) Frage: Für das Beispiel "Hallo" -> Wie schreibt und ließt man richtig in und aus Streams? :pale:

[Edit]@dizzy: Wieso um 4 zurück? Da könntest du doch was verpassen, einmal liest du bsw. 'lo...' und nach dem zurückspringen '..Hal'!? (Wenn ich das richtig sehe).[/Edit]

Muetze1 20. Aug 2004 22:46

Re: [Streams]: existierende Daten entfernen / einfügen
 
Moin!

S ist ein AnsiString und daher nur ein Zeiger auf den String. Daher ergibt SizeOf() auch eine 4, weil es ein Pointer ist. Somit folgendes:

1. Nutze anstatt SizeOf() die Funktion Length() um die Länge des Strings zu ermitteln.
2. Gebe der Schreibroutine das erste Zeichen an.

Delphi-Quellcode:
 S := 'Hallo';
 WriteBuffer(S[1], Length(S));
MfG
Muetze1

F.W. 21. Aug 2004 00:34

Re: [Streams]: existierende Daten entfernen / einfügen
 
:thumb: Das funktioniert! :thumb:

:idea: Stelle fest: Auslesen funktioniert dann folgender Maßen
Delphi-Quellcode:
const
 L: Integer = 5; //Länge
var
 S: Array[0..MAX_PATH-1] of Char;
//oder S: Array[0..L-1] of Char;
 FS: TFileStream;
    { ... }
 FS.ReadBuffer(S, L);

Soweit hätten wirs damit schonmal :!:

F.W. 23. Aug 2004 18:11

Re: [Streams]: existierende Daten entfernen / einfügen
 
Da gibt's doch noch was besseres (meine Methode geht zwar auch, aber das hab ich in nem Tut gelesen):

Delphi-Quellcode:
var
 S: String;
begin
   { ... }
 SetLength(S, Len);
 FS.ReadBuffer(S[1], Len);
   { ... }
end;
:dancer2: Soviel dazu!

Dani 9. Mär 2005 15:27

Re: [Streams]: existierende Daten entfernen / einfügen
 
Zitat:

Zitat von Luckie
Wenn du mitten reinschreiben willst, dann wird dir nichts anderes übrigbleiben, als ab der Stelle den Rest in einem memoryStream zwischenzuspeichern, deinen Datensatz reinschreiben und dann den gesicherten Rest wieder dranzuhängen.

Das ist nicht akzeptabel, ich kann doch nicht bei einem 100 MB großen Archiv mal eben 99,99 MB in den RAM auslagern, nur weil ich einen Kommentarstring im Header ändern will!? Gibt es denn gar keine andere Lösung?

Jens Schumann 9. Mär 2005 16:13

Re: [Streams]: existierende Daten entfernen / einfügen
 
Hallo,
Zitat:

Zitat von Dani
Zitat:

Zitat von Luckie
Wenn du mitten reinschreiben willst, dann wird dir nichts anderes übrigbleiben, als ab der Stelle den Rest in einem memoryStream zwischenzuspeichern, deinen Datensatz reinschreiben und dann den gesicherten Rest wieder dranzuhängen.

Das ist nicht akzeptabel, ich kann doch nicht bei einem 100 MB großen Archiv mal eben 99,99 MB in den RAM auslagern, nur weil ich einen Kommentarstring im Header ändern will!? Gibt es denn gar keine andere Lösung?

bei komplexeren Formaten würde ich nicht den klassischen Stream verwenden, sondern würde über das IStorage Interface gehen. Mit diesem Interface kann man innerhalb einer Datei ein "Dateisystem" anlegen. Man kann sich wie den Windows-Explorer vorstellen.
Das IStorage Interface gibt es schon so lange, dass es sogar in der Win32 Referenz, die mit Delphi geliefert wird beschrieben wird. Mit ein bißchen COM Kenntnissen und googeln sollte es nicht all zu schwierig werden.
Eine Datei mit Header mit Datenteil würde dann intern so aussehen
Code:
Root
  |----Header
  |----Daten
Man kann dann nur in den Header schreiben (so viel man möchte). Der Datenteil bleibt davon unberührt.

shmia 9. Mär 2005 16:19

Re: [Streams]: existierende Daten entfernen / einfügen
 
Zitat:

Zitat von mytar
Ich hab eine Datei, und öffne sie via Stream, nun möchte ich mit Seek() die entsprechende Position suchen, und dann was in den Stream einfügen, oder herauslöschen. Die Datei hab ich zuvor selbst erzeugt, ich kenne also die Dateistruktur.

Zitat:

Zitat von Luckie
Wenn du mitten reinschreiben willst, dann wird dir nichts anderes übrigbleiben, als ab der Stelle den Rest in einem memoryStream zwischenzuspeichern, deinen Datensatz reinschreiben und dann den gesicherten Rest wieder dranzuhängen.

Was Lucky sagt, ist so korrekt und daran führt kein Weg vorbei.
Theoretisch könnte man alle 8kByte (die Clustergrösse) weitere Cluster einfügen oder löschen.
Praktisch kannst du eine Datei auf Festplattenebene nicht manipulieren ohne sehr viel Aufwand zu betreiben.

Alle Dateiformate für Datenbanken gehen nun so vor, dass ein Block oder Datensatz als gelöscht markiert wird und neue Daten ans Dateiende geschrieben werden.
Nach einige Zeit enthält die Datei Löcher und kann wesentlich mehr Platz auf der Platte brauchen, als Nutzdaten vorhanden sind.
Dann ist eine Komprimierung der Daten fällig. (Nutzdaten werden in neue Datei kopiert, alte Datei geöscht und Neu -> Alt umbenamst)

Also denk dir mal ein schlaues Datenformat aus. Eine Archivdatei könnte z.B. folgenden Aufbau haben:
Code:
Datensatzname: string(32);
Nutzdatensize: integer;
blocksize: integer;     // immer > oder = Nutzdatensize
Flags: Cardinal;       // 1=gelöscht
[nutzdaten.....][evtl. unbenutzte Daten]

Dani 9. Mär 2005 16:31

Re: [Streams]: existierende Daten entfernen / einfügen
 
Dann werde ich mich mal in den Umgang mit dem IStorage Interface einarbeiten. Danke für den Tipp =)

Muetze1 9. Mär 2005 16:34

Re: [Streams]: existierende Daten entfernen / einfügen
 
Moin!

Naja, ich würde trotzdem Luckies Aussage abwandeln und sagen, das man sich ein temporäres Stream Objekt anlegt. Dabei ist der Typ dann die Sache des Programmierers. Wenn ich weiss, das es ein 100 MB Archiv ist, dann würde ich in einem TFileStream das ganze zwischenspeichern bzw. darin neu zusammenbauen. Bei deutlich kleineren Datenmengen wäre ein TMemoryStream angebracht. Es ist wirklich nicht ein Glanzstück mal schnell den Speicher mit 100 MB voll zu stopfen, so dass Windows vielleicht noch anfängt auf kleineren Rechnern erstmal stundenlang auszulagern. Da wäre dann der direkte Weg auf die Festplatte effizienter.

MfG
Muetze1

mytar 17. Mär 2005 16:52

Re: Streams: existierende Daten entfernen / einfügen
 
Ich denke diese IStorage-Interface ist eine gute Möglichkeit!

Wenns aber schnell umgeschrieben werden muss, ist eine temporäre Datei
auch sinnvoll.

Viele Compression-Tools machen es glaub ich auch auf diesem Weg!

mytar 28. Mär 2005 09:58

Re: [Streams]: existierende Daten entfernen / einfügen
 
Zitat:

Zitat von shmia
Alle Dateiformate für Datenbanken gehen nun so vor, dass ein Block oder Datensatz als gelöscht markiert wird und neue Daten ans Dateiende geschrieben werden.
Nach einige Zeit enthält die Datei Löcher und kann wesentlich mehr Platz auf der Platte brauchen, als Nutzdaten vorhanden sind.
Dann ist eine Komprimierung der Daten fällig. (Nutzdaten werden in neue Datei kopiert, alte Datei geöscht und Neu -> Alt umbenamst)

Nenn man so etwas die Datenbank reorganisieren?

Nur interesse halber?

mytar 29. Mär 2005 08:13

Re: Streams: existierende Daten entfernen / einfügen
 
*push* :)


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