Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Datei an Datei anhängen (https://www.delphipraxis.net/154806-datei-datei-anhaengen.html)

MiniMax 26. Sep 2010 12:13

Datei an Datei anhängen
 
Hallo Zusammen,
ich habe da nen Problem (mal wieder):

Ich bekomme beim Speichern ein Text File und ein JPG Bild.

Ich möchte nun das JPG Bild an die Text datei an hängen, sodass ich nur noch eine Datei habe.
Allerdings muss ich mit meinem Programm später diese Kombi Datei laden können und Die Text datei anzeigen lassen lassen (in ner Memo) und das JPG Bild in nem Image.

Nun meine Frage(n):
Geht dass überhaupt?
Wenn ja könnte jemand mir sagen (aufzeigen) wie das geht (code snippet):thumb:

Hoffe auf Antworten

mkinzler 26. Sep 2010 12:16

AW: Datei an Datei anhängen
 
Ich würde die beiden Dateien dann eher in ein Archiv oder anderen Container packen

zeras 26. Sep 2010 12:17

AW: Datei an Datei anhängen
 
Du kannst vorher einen Header integrieren, wo drin steht, ab welchem Index die Textdatei und ab welchem Index dann das Bild. Das müßte über Streams zu machen sein. Ein Beispiel habe ich aber im Moment nicht.

SirThornberry 26. Sep 2010 12:18

AW: Datei an Datei anhängen
 
das geht. Eine Datei kann beliebige Daten enthalten und du musst dir lediglich Gedanken darüber machen wie du die Daten darin ablegst.
Eine einfache Variante vor den Daten immer zu hinterlegen wie groß diese sind. Damit kannst du beliebig viele Datenblöcke (in deinem Fall verschiedene Dateien) in eine Datei stopfen und es auch wieder auseinander nehmen.
Üblicherweise schreibt man an den Anfang der Datei eine eindeutige Kennung um beim öffnen festzustellen ob es auch wirklich der richtige Dateityp ist (damit man die folgenden Daten nicht falsch interpretiert).

MiniMax 26. Sep 2010 12:25

AW: Datei an Datei anhängen
 
mhmm :?:

Wie bekomme ich den ein jpg in eine Stringlist? Und Später wieder zurück in eine JPG?
Eine Textdatei dürfte ja kein Prob sein. ??

SirThornberry 26. Sep 2010 12:26

AW: Datei an Datei anhängen
 
Warum in eine Stringlist? Ich denke es geht um eine Datei.
Du kannst sowohl eine Stringlist in einen Stream (TFileStream) als auch ein JPG in einen Stream speichern.

rollstuhlfahrer 26. Sep 2010 12:29

AW: Datei an Datei anhängen
 
ganz einfach: Du nimmst keine Stringliste, sondern Streams. Zuerst öffnest du den einen Stream und schreibst die Länge des Inhaltes vom Memo rein. Dann ein Trennungszeichen (du willst ja später wissen, wie lang und nicht den Text). Dann kannst du den kompletten Text per .SaveToStream() aus dem Memo holen. Danach schreibst du das JPEG mittels .SaveToStream() in den gleichen Stream. Fertig.

Bernhard

SirThornberry 26. Sep 2010 12:31

AW: Datei an Datei anhängen
 
Ein Trennzeichen ist nicht notwendig da die Länge zum Beispiel als Cardinal gespeichert werden kann. Und dieser hat immer die gleiche Größe (SizeOf).

rollstuhlfahrer 26. Sep 2010 12:36

AW: Datei an Datei anhängen
 
man sieht wohl, dass ich meine Zahlen gerne als Text schreibe (also wie auf der Tastatur). Dann braucht man das Trennzeichen. Nimmt man Zahlen als Datentyp dann nicht, richtig.

Bernhard

MiniMax 26. Sep 2010 12:42

AW: Datei an Datei anhängen
 
Mom,
ich komme da nicht mit:
also deklariere ich erstmal nen stream?
Dann SChreibe ich meine Memo werte da rein?
Dann nen Trennzeichen ?
und dann das Bild?

also so?

Delphi-Quellcode:
procedure Button1.click (sender: TObject);
var
MyStream: Stream;
Imagejpg: JPEG;
Trennzeichen: String;
begin
Memovirtual.savetostream(Mystream);
Trennzeichen:= '<begin JPG>';
Trennzeichen.savetostream(Mystream);
Imagejpg:= Loadfromfile('./Bild.jpg');
Imagejpg.savetoStream(MyStream);

Mystream.savetofile(Meinmixstream.abc);
end;
Ist dass so richtig?

SirThornberry 26. Sep 2010 12:43

AW: Datei an Datei anhängen
 
Um das ganze mit einem Texteditor lesen zu können ist das sicher eine schöne Variante. Da aber auch ein JPEG mit in die Datei soll bietet es sich an alles binär zu speichern.

ungetesteter Code:
Delphi-Quellcode:
var
  lStream: TStream;
  lStartPos: Int64;
  lDataSize: Cardinal;
begin
  lStream := TFileStream.Create(YourFileName, fmCreate);
  try
    // Memo speichern
    lStartPos := 0;
    lStream.Position := lStream.Position + sizeof(lDataSize);
    YourMemo.Lines.SaveToStream(lStream);
    lDataSize := lStream.Position - lStartPos - sizeof(lDataSize);
    lStream.Position := lStartPos;
    lStream.Write(lDataSize, sizeof(lDataSize));
    // JPG speichern
    lStartPos := lStream.Size;
    lStream.Position := lStream.Position + sizeof(lDataSize);
    YourJPG.SaveToStream(lStream);
    lDataSize := lStream.Position - lStartPos - sizeof(lDataSize);
    lStream.Position := lStartPos;
    lStream.Write(lDataSize, sizeof(lDataSize));
  finally
    lStream.Free;
  end;
[Edit]
Wenn etwas unklar ist am Quelltext bitte nachfragen (nichts ist schlimmer als einfach abzutippen anstelle zu verstehen)

mkinzler 26. Sep 2010 12:45

AW: Datei an Datei anhängen
 
-Länge 1. datei
-Inhalt 1. datei
-Länge 2. Datei
-Inhalt 2. Datei
...

sx2008 26. Sep 2010 12:48

AW: Datei an Datei anhängen
 
Du hast die Wahl zwischen:
1.) das Rad neu erfinden
du denkst dir ein eigenes Format aus (Mit einem Header, der Länge und Name der Datei enthält)
2.) professionelle Vorgehensweise
a.) sich für ein Standard-Archivformat entscheiden
(z.B. .zip, *.cab, *.tar,..)
b.) Komponenten oder Klasse für das Archivformat besorgen
(z.B. auf Torry's)

MiniMax 26. Sep 2010 12:49

AW: Datei an Datei anhängen
 
Den code werde ich nachher gelich mal testen --> thx dafür.

Wie bekomme ich denn die Datein wieder Getrennt und in einen Memo und ein Image geladen?

SirThornberry 26. Sep 2010 12:50

AW: Datei an Datei anhängen
 
Ich würde das ganze nicht als "Rad neu erfinden" bezeichnen sondern als Lösung maßgeschneiderte Lösung. Denn wozu soll man das ganze noch packen und den Quelltext mit verschiedenen Algorythmen des Formates aufblähen wenn man letzendlich nur mehrere Daten in einem Stream speichern will.

Wenn du den Code verstanden hast weißt du auch wie der umgekehrte Weg lautet (lesen aus einem Stream geht mit read anstelle von write)
Deswegen auch mein Kommentar das du nachfragen sollst wenn du am Code etwas nicht verstehst.

Luckie 26. Sep 2010 12:50

AW: Datei an Datei anhängen
 
Zitat:

Zitat von MiniMax (Beitrag 1052044)
Ist dass so richtig?

Probiere aus, ob du es wieder geladen bekommst. Aber ich würde kein Trennzeichen nehmen, denn das muss man bei Laden erst wieder suchen. Schreibe stattdessen an den Anfang die Länge des Textes.

SirThornberry 26. Sep 2010 12:52

AW: Datei an Datei anhängen
 
Zudem kann es vorkommen dass, das Trennzeichen in den Daten vorkommt. Entsprechend macht es mehr Arbeit das Trennzeichen zu suchen und in den Daten zu ersetzen als gleich darauf zu verzichten.
Natürlich kann man das ganze auch kombinieren in dem man die Länge + Trennzeichen nutzt aber das ist bei binärer Speicherung der Länge eben nicht notwendig.

MiniMax 26. Sep 2010 12:58

AW: Datei an Datei anhängen
 
Ok dann frage ich ma:

Delphi-Quellcode:

var
  lStream: TStream;
  lStartPos: Int64;
  lDataSize: Cardinal;
begin
  lStream := TFileStream.Create(YourFileName, fmCreate); //stream erstellen?
  try
    // Memo speichern
    lStartPos := 0; //wozu die Position heraus finden?
    lStream.Position := lStream.Position + sizeof(lDataSize); //was wird hier gemacht?
    YourMemo.Lines.SaveToStream(lStream); //is klar wird gespeichert
    lDataSize := lStream.Position - lStartPos - sizeof(lDataSize); //was wird hier gemacht`?
    lStream.Position := lStartPos; //warum den Zeiger verstellen?
    lStream.Write(lDataSize, sizeof(lDataSize)); //was wird hier reingeschrieben?

    // JPG speichern
    lStartPos := lStream.Size; //größe setzen wo der stream begginnt?
    lStream.Position := lStream.Position + sizeof(lDataSize); //was wird hier gemacht?
    YourJPG.SaveToStream(lStream); // Speichern is klar
    lDataSize := lStream.Position - lStartPos - sizeof(lDataSize); //??
    lStream.Position := lStartPos; //Warum den Zeiger Verstellen?
    lStream.Write(lDataSize, sizeof(lDataSize)); //was wird hier gemacht
  finally
    lStream.Free; //is klar
  end;
Warum ich so viele Fragen habe, ich habe noch nie mit streams gearbeitet :oops:

rollstuhlfahrer 26. Sep 2010 12:59

AW: Datei an Datei anhängen
 
Mit TFilestream die Datei wieder öffnen. Dann kannst du die Länge wieder auslesen. Nachdem du die Länge hast, schreibst du alles, was sich danach befindet in dein Memo. Allerdings nur so oft, wie in der Länge angegeben. Selbiges machst du mit dem JPEG.

Delphi-Quellcode:
procedure Laden();
var
  lStream: TStream;
  lStartPos: Int64;
  lDataSize: Cardinal;
  TextStream, JPEGStream: TMemoryStream;
begin
  lStream := TFileStream.Create(YourFileName, fmOpenRead);
  try
    // Länge lesen
    lStream.Read(lDataSize, sizeOf(lDataSize));

    TextStream := TMemoryStream.Create;
    TextStream.Size = lDataSize;
    // Text auslesen
    lStream.Read(TextStream.Memory, lDataSize);
    YourMemo.Lines.LoadFromStream(TextStream);
    TextStream.Free;

    // Bild laden
    lStream.Position := sizeof(lDataSize) + lDataSize; // Diese Zeile sollte weggelassen werden können, da der Stream ja schon die richtige Position hat.

    // Länge lesen
    lStream.Read(lDataSize, sizeOf(lDataSize));

    JPEGStream := TMemoryStream.Create;
    JPEGStream.Size = lDataSize;
    // Text auslesen
    lStream.Read(JPEGStream.Memory, lDataSize);
    YourJPEG.LoadFromStream(JPEGStream);
    JPEGStream.Free;
  finally
    lStream.Free;
  end;
end;
ungetestet, sollte aber funktionieren.

Bernhard

ADD: Was der Code von SirThornberry macht ist eigentlich nicht schwer: Er erstellt einen Stream (Filestream zum Lesen/Schreiben von Dateien). In diesen Stream wird eine 0 (Datentyp: Cardinal) geschrieben. Dann kommt der Text rein. Streamlänge - Länge von Cardinal = Textlänge. Diese Textlänge wird jetzt ganz vorne hingeschrieben. Danach macht er hintendran weiter: 0 (Cardinal) reinschreiben, dann das Bild hintendran. Jetzt noch die Länge des Bildes berechnen und die 0 vor dem Bild ersetzen, fertig.

MiniMax 26. Sep 2010 13:02

AW: Datei an Datei anhängen
 
Woher weiß den der Code, wie lang der Text ist und das jpg? Der kennt doch nur die gesamt länge?

rollstuhlfahrer 26. Sep 2010 13:03

AW: Datei an Datei anhängen
 
Siehe Edit obendrüber: Es werden die einzelnen Längen in die Datei geschrieben und wieder ausgelesen.

Bernhard

SirThornberry 26. Sep 2010 13:06

AW: Datei an Datei anhängen
 
Such in dem Quelltext mal nach lDataSize. Das ist die Variable welche die Länge der Daten enthält und in die Datei geschrieben wird und umgekehrt.

Das Prinzip beim Speichern ist folgendes:
- Platz lassen für Größe der folgenden daten
- Daten schreiben
- Schauen wie groß die geschriebenen Daten waren
- Größe der geschriebenen Daten am Anfang platzieren wo wir Platz dafür gelassen haben.

MiniMax 26. Sep 2010 13:13

AW: Datei an Datei anhängen
 
ah jetzt hab ich es Verstnanden! Werde es eben Ausprobieren

xZise 26. Sep 2010 13:34

AW: Datei an Datei anhängen
 
Moin,
das Trennzeichen hat aber den Vorteil, dass die Länge nicht begrenzt ist. Außerdem braucht man mit 4 Byte am Anfang, wenn gar kein Text drin steht, sondern nur 1 oder 2 (je nach Kodierung).

Und es gibt viele die nicht das Rad neu erfinden: jars, Open Document, Office Open XML Dokumente verwenden alle *.zip zum komprimieren.

MfG
Fabian

mkinzler 26. Sep 2010 13:36

AW: Datei an Datei anhängen
 
Wenn man die Länge aber kennt, könnte man, wenn man die 2. Datei Einlesen will, direkt den Datensatzzeiger richtig positionieren.

rollstuhlfahrer 26. Sep 2010 13:38

AW: Datei an Datei anhängen
 
Also bitte: 4 GB Text und 4 GB als JPEG sind auch in fernerer Zukunft so schnell noch nicht erreicht. Selbst wenn: Dann ändert man Cardinal auf Int64 und hat die Probleme bis in alle Ewigkeit verschoben.

Bernhard

Sir Rufo 26. Sep 2010 13:40

AW: Datei an Datei anhängen
 
Zitat:

Zitat von xZise (Beitrag 1052084)
Moin,
das Trennzeichen hat aber den Vorteil, dass die Länge nicht begrenzt ist. Außerdem braucht man mit 4 Byte am Anfang, wenn gar kein Text drin steht, sondern nur 1 oder 2 (je nach Kodierung).

Und es gibt viele die nicht das Rad neu erfinden: jars, Open Document, Open Office XML Dokumente verwenden alle *.zip zum komprimieren.

MfG
Fabian

Selbst MS nutzt das ZIP-Format für die neuen Office-Dokumente

Luckie 26. Sep 2010 13:44

AW: Datei an Datei anhängen
 
Zitat:

Zitat von xZise (Beitrag 1052084)
Moin,
das Trennzeichen hat aber den Vorteil, dass die Länge nicht begrenzt ist.

Und den Nachteil, dass man es beim Einlesen suchen muss. Will ich nur das JPEG haben, kann ich direkt an den Anfang des JEPGS springen und es auslesen. Ich denke die Vorteile überwiegen hier die Nachteile.

Aber warum das nachträgliche schreiben der Textlänge? Die kann ich doch schon vorher ermitteln und gleich schreiben.

SirThornberry 26. Sep 2010 13:46

AW: Datei an Datei anhängen
 
Das nachträgliche Schreiben weil ich es allgemein halten wollte. Beim JPEG weiß ich erst nach dem schreiben wie groß es ist. Natürlich könnte man es in einem Memorystream zwischen speichern aber das kann man sich eben sparen in dem man nachträglich die Länge schreibt.
Und beim ermitteln der Textlänge ist es ja eigentlich auch nicht anders. Wenn man da Length(Memo.lines.text) abruft wird auch erstnochmal der Text abgerufen nur um die Länge zu ermitteln. Und das spart man sich damit ebenfalls.

Luckie 26. Sep 2010 13:48

AW: Datei an Datei anhängen
 
Wenn es wirklich nur eine Text und ein JPEG hat, braucht er die Größe des JPEGs nicht zum Auslesen. Einfach ans Ende des Textes springen, wir wissen ja wie lang er ist, und dann bis zum Dateiende lesen.

rollstuhlfahrer 26. Sep 2010 13:48

AW: Datei an Datei anhängen
 
Für den Text mag das vielleicht gelten, aber es gibt meines Wissens keine Möglichkeit, die Größe eines JPEGs, welches sich im Speicher befindet, zu ermitteln, die es anschließend auf der Festplatte haben wird. Hinzu kommt vor allem bei JPEG noch die Kompression, wodurch man nicht sagen kann, die groß das JPEG jetzt wirklich wird.

Bernhard

Luckie 26. Sep 2010 13:52

AW: Datei an Datei anhängen
 
Zum Schreiben musst du es auch gar nicht wissen, wenn es nur ein Text mit einem JPEG ist. Dann schreibst du eben so lange, bis das ganze JPEG geschrieben ist. Und wenn du die Größe zum Auslesen brauchst, kannst du sie dir ausrechnen: Dateigröße - Header - Text(länge).

mkinzler 26. Sep 2010 14:00

AW: Datei an Datei anhängen
 
Wenn es bei den 2 Dateien bleibt

MiniMax 26. Sep 2010 14:03

AW: Datei an Datei anhängen
 
So habe es erstmal mit dem Zusammenfügen getestet:

Delphi-Quellcode:
procedure TForm1.Zusammenfügen;
var
  lStream: TStream;
  lStartPos: Int64;
  lDataSize: Cardinal;
  //bildchen:jpeg;
begin
  lStream := TFileStream.Create('meinStream.ampstr', fmCreate);
  try
    // Memo speichern
    lStartPos := 0;
    lStream.Position := lStream.Position + sizeof(lDataSize);
    memo1.Lines.SaveToStream(lStream);
    lDataSize := lStream.Position - lStartPos - sizeof(lDataSize);
    lStream.Position := lStartPos;
    lStream.Write(lDataSize, sizeof(lDataSize));
    // JPG speichern
    lStartPos := lStream.Size;
    lStream.Position := lStream.Position + sizeof(lDataSize);

    image1.savetostream(lStream);
    lDataSize := lStream.Position - lStartPos - sizeof(lDataSize);
    lStream.Position := lStartPos;
    lStream.Write(lDataSize, sizeof(lDataSize));
  finally
    lStream.Free;
  end;
end;
Es kommt ein Fehler bei der Zeile
Delphi-Quellcode:
    image1.savetostream(lStream);
Code:
[DCC Fehler] Unit1.pas(110): E2003 Undeklarierter Bezeichner: 'savetostream'
Was is falsch?

SirThornberry 26. Sep 2010 14:05

AW: Datei an Datei anhängen
 
Image1 ist kein JPG. Der bisher gezeigte Code war für das Speichern eines JPG's
Ein ganzes TImage speichern macht auch keinen Sinn, oder willst du Transparenzfarbe, größe auf der Form, Stretchmodus, Anchors etc. davon speichern?
Also einfach überlegen was du wirklich speichern willst und schauen ob es da ein SaveToStream gibt.

xZise 26. Sep 2010 14:05

AW: Datei an Datei anhängen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1052090)
Zitat:

Zitat von xZise (Beitrag 1052084)
[...]Und es gibt viele die nicht das Rad neu erfinden: jars, Open Document, Open Office XML Dokumente verwenden alle *.zip zum komprimieren.[...]

Selbst MS nutzt das ZIP-Format für die neuen Office-Dokumente

Argh ein Verdreher, aber Office Open XML ist das neue Format von Office (docx etc.).

Und wegen der Länge: Wenn die JPG im Stream drin ist, dann ist sie ja fertig kodiert etc. das heißt man kennt schon deren Größe. Ein anderer Weg wäre die Länge hinten zu speichern. Bei Schreiben wird dann direkt hintereinander weg geschrieben, und beim lesen wird die letzte Größe gelesen, soweit nach vorne gesprungen und dann eingelesen werden:
Code:
i := Lese letzten Cardinal
Mache solange
  Springe i Bytes - Cardinalbreite * 2 zurück
  j := Lese Cardinal (= Länge von den Daten davor)
  Lese i Bytes
  Springe (i + j) Bytes - Cardinalbreite * 2 zurück
  i := j;
bis Position <= 0
Der aktuelle Weg wäre auch mit einem Pufferstream möglich. Darein kopiert man den Inhalt nimmt die Länge, schreibt sie, und kopiert dann den Inhalt des Pufferstreams in den echten Dateistream.

[redbox]Statt Image1.SaveToStram mach mal lieber Image1.Picture.SaveToStream. Das TImage zeigt nur ein TPicture an, das heißt speichern kann nur das Bild selber (und nicht der "Anzeiger").[/redbox]

[redbox #2]TImage selber geht nicht zu speichern, nur das Bild, was es geladen hat.[/redbox #2]

MfG
Fabian

rollstuhlfahrer 26. Sep 2010 14:07

AW: Datei an Datei anhängen
 
Ganz einfach: Du willst doch das Bild speichern und nicht den Container. Also brauchst du: (Image1.Picture.Graphic as TJPEGImage).SaveToStream();
Sollte sich mal kein JPEG in dem Image befinden, gibts hier ne Exception.

Bernhard

xZise 26. Sep 2010 14:14

AW: Datei an Datei anhängen
 
Zitat:

Zitat von rollstuhlfahrer (Beitrag 1052116)
Ganz einfach: Du willst doch das Bild speichern und nicht den Container. Also brauchst du: (Image1.Picture.Graphic as TJPEGImage).SaveToStream();
Sollte sich mal kein JPEG in dem Image befinden, gibts hier ne Exception.

Bernhard

Oder man spart sich den Cast? Weil TGraphic (und btw auch TPicture) können in einem Stream speichern. Wenn man es unbedingt in einen JPG haben will:
Delphi-Quellcode:
var
  jpg : TGraphic;
begin
  jpg := TJPEGImage.Create();
  try
    jpg.Assign(Image1.Picture.Graphic);
    jpg.SaveToStream(stream);
  finally
    jpg.Free;
  end;
end;
So brauchst du nur den Konstruktor ändern und kannst es in alles andere speichern, sofern es von TGraphic erbt. Und du hast keine Exception und es ist irrelevant was im Image1 steht (imho).

MfG
Fabian

SirThornberry 26. Sep 2010 14:21

AW: Datei an Datei anhängen
 
Ist das alles überhaupt nötig? Ist SaveToStream nicht eine abstrakte Methode von TGraphic so das man sich jeden Cast etc. sparen kann?

rollstuhlfahrer 26. Sep 2010 14:22

AW: Datei an Datei anhängen
 
Zitat:

Zitat von xZise (Beitrag 1052122)
Oder man spart sich den Cast? Weil TGraphic (und btw auch TPicture) können in einem Stream speichern.

Du sparst dir zwar den Cast, riskierst aber, dass du die Datei nicht mehr laden kannst, weil einfach kein JPEG gespeichert wurde. Das Problem ist: Der Image-Container schafft es, die Dateieendungen zu den Bildtypen zuzuordnen. Bei Streams sieht das anders aus. Raten macht er nicht und iterativ geht er auch nicht durch. Du musst also dem TJPEGImage einen JPEG-Stream geben. Wenn du jetzt beim speichern gerade zufällig kein JPEG erwischt hast, sondern ein Bitmap, wirds kriminell. Du speicherst erfolgreich dein Bitmap, schaffst es aber nicht mehr dein JPEG zu laden, weil du ja ein Bitmap hast.

Bernhard

ADD: Ja, ansonsten kann man auf den Cast verzichten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:57 Uhr.
Seite 1 von 2  1 2      

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