Autor |
Beitrag |
mexx
      
Beiträge: 1183
|
Verfasst: Fr 13.04.07 16:02
Ich verwende die FastReport-Komponenten und speichere einen Report wie folgt in einen Blob-Feld einer FireBird-Datenbank.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| ... var MemStream: TStream; begin ... MemStream := TMemoryStream.Create; MemStream.Position := 0; FastReport.Report.SaveToStream(MemStream); QueryInsertReport.ParamByName('FastReport').LoadFromStream(MemStream,ftBlob); ... end; |
Die Verfahrensweise habe ich von einer Anleitung für den FastReport. Mit einer ShowMessage auf das Value des Parameters von 'QueryInsertReport.ParamByName('FastReport')' sehe ich, dass Einträge im Report wie ü,ä und ö verändert wurden. Die Umlaute sind nun ##. Speichere ich den Report als Datei passiert das nicht. Speicher ich andere Daten mit Umlauten in der Datenbank, verändern sich die Daten auch nicht.
Es muss also irgendwas beim 'SaveToStream(MemStream)' oder beim 'ParamByName('FastReport').LoadFromStream(MemStream,ftBlob)' mit dem Stream passieren. Aber wie finde ich das raus und welche Möglichkeiten habe ich, das Speichern des Reports als Blob in der Datanbank anders zu machen?
mexx
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Fr 13.04.07 16:22
ist es vielelicht die Datenbank, die einen Zeichensatz benutzt, der das automatisch ändert ? Ich glaube, ich hatte mal sowas bei Firebird, seitdem nehme ich immer CharSet NONE 
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Fr 13.04.07 16:31
mexx hat folgendes geschrieben: | Speicher ich andere Daten mit Umlauten in der Datenbank, verändern sich die Daten auch nicht. |
Ich bin dankbar für jeden Tipp. Aber das kann ich ausschließen.
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Fr 13.04.07 16:55
Moin!
Nur zur Sicherheit: vor dem .LoadFromStream setzt du .Position := 0, oder?
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Fr 13.04.07 17:26
und man kann auch für blob-feld-definitionen ein charset setzen, welches anders ist als das globale der datenbank. Es gibt auch verschiedene typen von Blobfeldern bei Firebird zum Bsp
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 07:59
@Narses: Ja, aber das nimmt keinen Einfluss. Da das BlobFeld in der Datenbank SubType 1 ist, kann ich mit einen Datanbank-Editor darauf zugreifen und sehe, dass bereits dort die Umlaute keiner Umlaute mehr sind.
@HelgeLange: Ganz wichtig zu wissen ist, dass es sich bei der Query NICHT um die Datenmenge aus der Datenbank handelt, sondern um eine Ergebnismenge einer Datenbankprocedure. Deswegen ist es nicht möglich das Blob als Feldinhalt, als FieldByName('Blob').Value := BlobStream, zu übergeben. Ich muss es als Parameter einer Query übergeben. Bei einen Parameter kann ich jedoch nur den Typ deklarieren. Kein Charset! Der BlobTyp in der Datenbank ist SubType 1. Also Text.
Ich bin mir sicher, dass der Fehler in der Übergabe des Reports an den Parameter liegt, aber welche Möglichkeiten habe ich, es anders zu machen. Ich kenne nur diese Syntacs.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| ... var MemStream: TStream; begin ... MemStream := TMemoryStream.Create; MemStream.Position := 0; FastReport.Report.SaveToStream(MemStream); QueryInsertReport.ParamByName('FastReport').LoadFromStream(MemStream,ftBlob); ... end; |
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 16.04.07 08:17
Von Firebird und den Blobs habe ich keine Ahnung: Aber bist du dir sicher, das der Report im ASCII-Format im Stream gespeichert wird? Ich gehe mal davon aus, das da der Haken ist: FastReport erzeugt einen Byte-Stream (also nix 'TEXT') und der soll dann in einem TEXT-Blob abgelegt werden. Da wird FB mit Sicherheit konvertieren und -rumms- sind die Daten futsch. Ich kenn das von MSSQL jedenfalls so.
Falls Du keine andere Möglichkeit hast, dann konvertiere den Stream in eine HEX-Zahlenfolge und speichere diesen 'Text' dann ab. Dann sind die Reports zwar doppelt so groß, aber was solls.
_________________ Na denn, dann. Bis dann, denn.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 08:20
alzaimar hat folgendes geschrieben: |
Falls Du keine andere Möglichkeit hast, dann konvertiere den Stream in eine HEX-Zahlenfolge und speichere diesen 'Text' dann ab. Dann sind die Reports zwar doppelt so groß, aber was solls. |
Das klingt vielversprechend. Kannst Du mir bitte zeigen wie das geht oder mir ein Link mit Infos geben? Ich weiß nicht, wie man ein Stream in HEX wandelt!
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 16.04.07 08:50
Such mal nach HexToBin und BinToHex in der Classes-Unit.
Generell sollte es so klappen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| Function FastReportStreamToHexString (sFastReport : TMemoryStream) : String; Var p : PChar;
Begin setLength (Result, 2*sFastReport .Size); P := PChar (sFastReport Memory); BinToHex (P, PChar (Result), sFRT.Size); End;
Procedure StringToFastReportStream (aString : String; sFastReport : TMemoryStream); Var p : PChar;
Begin sFastReport.Size := Length (aString) div 2; P := PChar (sFastReport Memory); HexToBin (PChar (aString), P, Length (aString)); End; |
Ist ungetestet, sollte aber funktionieren.
_________________ Na denn, dann. Bis dann, denn.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 09:18
Ich hab es wie folgt.
Lesen
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| ... var BlobStream: TMemoryStream; ... BlobStream := TMemoryStream.Create; BlobStream := CreateBlobStream(FieldByName('FAST_REPORT'),bmRead); BlobStream.Position := 0; MainFstRpt.LoadFromStream(BlobStream); BlobStream.Free; ... |
Fehler: [Fehler] FstRptModul.pas(325): Inkompatible Typen: 'TMemoryStream' und 'TStream'
Schreiben
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| function TFstReportModul.MainDesignerSaveReport(Report: TfrxReport; SaveAs: Boolean): Boolean;
Function FastReportStreamToHexString (sFastReport : TMemoryStream) : String; Var p : PChar; Begin setLength (Result, 2*sFastReport .Size); P := PChar (sFastReport); BinToHex (P, PChar (Result), sFastReport.Size); End;
... begin ... Blobstream := TMemoryStream.Create; MainFstRpt.Report.SaveToStream(BlobStream); ParamByName('FastReport').Value := FastReportStreamToHexString(BlobStream); BlobStream.Free; ... |
Den Fehler verstehe ich jedoch nicht.
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 16.04.07 09:27
Zu 1. Createblobstream erzeugt einen TBlobStream. Den müsstest Du in einen TMemoryStream kopieren, oder die StreamToString-Routine umschreiben, das der Hex-Code immer byteweise erzeugt wird. (Stichwort: 'TStream.CopyFrom')
Zu 2. Nun ist das Resultat der StreamToString-Funktion ein 'String'. Dein Feld ist aber ein BLOB.... (Stichwort: TStringStream)
_________________ Na denn, dann. Bis dann, denn.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 09:42
Ehrlich gesagt, ich verstehs nicht.
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 10:00
Da der Report eine XML-File ist, gehe ich davon aus, dass der BlobStream nichts weiter als diese XML-File ist. Kein Binärcode. Sondern der reine String. Liege ich das falsch?
Ein Blobfeld kann doch alle möglichen Inhalte tragen. Da spielt es doch keine Rolle, was ich dem Parameter gebe.
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 16.04.07 10:31
Oh, XML? Echt? Na dann sollte es funktionieren. Speichere doch mal das XML, so wie es von FR kommt und dann, wenn Du es wieder ausliest. Wo sind die Unterschiede? Besorg Dir 'Beyond Compare' oder WinDiff en.wikipedia.org/wiki/WinDiff.
_________________ Na denn, dann. Bis dann, denn.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 11:39
Können wir bitte nochmal über die Procedure StringToFastReportStream reden?
Ich muss der Procedure ja ein MemoryStream geben(HEX), diesen in Binär umwandeln und dann wieder in ein Stream zurück wandeln, weil ich einen Stream in den Reportdesigner laden muss.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function StringToFastReportStream (aString: String; sFastReport : TMemoryStream): TMemoryStream; Var p : PChar; Begin sFastReport.Size := Length (aString) div 2; P := PChar (sFastReport); HexToBin (PChar (aString), P, Length (aString)); Result := ??? End; |
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 11:41
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 16.04.07 11:57
Nee, das brauchst Du alles nicht, wenn dein Stream sowieso schon reinen ASCII (also XML) beinhaltet.
Dann tut es auch ein TStringStream.
Schreiben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| Var S : TStringStream;
Begin S:= TStringStream.Create(''); Try Report.SaveToStream (S); myQuery.ParamByName('FastReport').Value := S.DataString; Finally S.Free; End; End; |
Und wieder lesen:
Sei 'ReportString' der String aus der DB, der den FastReport enthält...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| Var S : TStringStream;
Begin S := TStringStream.Create (ReportString); Try Report.LoadFromStream (S); Finally S.Free; End End; |
Klappt denn jetzt alles?
_________________ Na denn, dann. Bis dann, denn.
|
|
mexx 
      
Beiträge: 1183
|
Verfasst: Mo 16.04.07 13:03
Leider nein! Der Umlaut wird immernoch falsch in die Datenbank geschrieben. Ich möchte nochmal auf das Verfahren mit der Umwandlung in HEX eingehen. Hier mal der aktuelle Code.
Schreiben
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| ... var BlobStream: TMemoryStream; ... function TFstReportModul.MainDesignerSaveReport(Report: TfrxReport;SaveAs: Boolean): Boolean;
Function FastReportStreamToHexString (sFastReport : TMemoryStream) : String; var p : PChar; begin setLength (Result, 2 * sFastReport .Size); P := PChar (sFastReport); BinToHex (P, PChar (Result), sFastReport.Size); end; ... begin ... Blobstream := TMemoryStream.Create; BlobStream.Position := 0; MainFstRpt.Report.SaveToStream(BlobStream); ParamByName('FastReport').Value := FastReportStreamToHexString(BlobStream); BlobStream.Free; ... |
FUNKTIONIERT!!
Ergebnis:24FA41006810F9037906000079060000002000001E00000024FA410000000000000000000000000000
0000001C0000001E000000010000000C00000044425465787441656E646572000000002A000000E0FC420000000
000088D4900642A8501F88E840100000000080000FF6000000000000000220000005CFE420000000000782F4...
Lesen
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:
| ... var LoadStream: TStream; ... function LoadReport(ShowDialog: Boolean;AMode: TReportMode; Sprache, AReportName: String):Boolean;
function HexStreamToBinStream (sFastReport : TStream): TStream; Var p : PChar; aString: String; Begin aString := StringOfChar(#00,sFastReport.Size); sFastReport.Size := Length (aString) div 2; P := PChar (sFastReport); HexToBin (PChar (aString), P, Length (aString)); Result.Write(P,Length(P)); End; ... begin
LoadStream := TStream.Create; LoadStream := HexStreamToBin (CreateBlobStream(FieldByName('FAST_REPORT'),bmRead)); MainFstRpt.LoadFromStream(LoadStream); LoadStream.Free; ... |
Ich brauche als Result von HexStreamToBinStream ein Stream, weil ich ein Stream als Report laden muss.
Fehler: Zugriffsverletzung bei 'Result.Write(P,Length(P));' Warum?
Danke für Deine Hilfe!
_________________ Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Mo 16.04.07 13:21
Hallo,
Vielleicht liegt es an den Daten mit Großbuchstaben??
In der Hilfe bei HexToBin:
Zitat: | Note: The hexadecimal number must use lower-case characters; HexToBin does not recognize upper-case characters. |
Oder aber einfach P dereferenzieren:
Delphi-Quelltext 1:
| Result.Write(P^,Length(P)); |
Gruß Horst
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 16.04.07 13:23
Du kannst keinen TStream deklarieren, das ist ein abstrakter Vorfahr für konkrete Implementierungen, wie TMemoryStream, TFileStream, TBlobStream etc. Du musst immer einen konkreten Stream deklarieren! Nur als Parameterdeklaration kann man einen TStream verwenden (der steht für 'T<irgendwas>Stream'
Du bekommst die Daten in einem TBlobStream (via CreateBlobStream). Du kannst nun selbst die Daten 2-Byte weise auslesen (Denn 2 Byte in Hex sind 1 Byte binär) und dann Byte-für-Byte alles in einen neuen Stream schreiben, der dann die Quelle für Fastreport ist.
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:
| Function HextStreamToByteStream (HexStream, OutStream : TStream); Var p : Word; b : Byte;
function HexChar(c: Byte): Byte; begin case Chr(c) of '0'..'9': Result := Byte(c) - Byte('0'); 'a'..'f': Result := (Byte(c) - Byte('a')) + 10; 'A'..'F': Result := (Byte(c) - Byte('A')) + 10; else Raise Exception.Create('Ungültiges HEX-Format') end; end;
function HexByte(p: Word): Byte; begin Result := HexChar(p shr 8) shl 4) + HexChar(p and $FF); end;
Begin HexStream.Seek (0, soFromBeginning); OutStream.Seek (0, soFromBeginning); While HexStream.Read (w, SizeOf (Word)) = SizeOf (Word) do Begin b := HexByte (w); OutStream.Write (b, SizeOf (b)); End End; |
Oder mit Hilfe eines TStringStreams überführst Du den BlobStream in einen String und konvertierst ihn zurück:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| Procedure StringToFastReportStream (aString : String; sFastReport : TStream); Var p : PChar;
Begin sFastReport.Size := Length (aString) div 2; P := PChar (sFastReport Memory); HexToBin (PChar (aString), P, Length (aString)); End; Function HextStreamToByteStream (HexStream, OutStream : TStream); Var S : TStringStream; Begin S := TStringStream.Create; S.CopyFrom (HexStream,0); StringToFastReportStream (S.DataString, OutStream); End; |
@Horst_H: Deshalb verwende ich gerne eine Funktion zusammen mit der Umkehrfunktion (HexToBin/BinToHex). Dann ist man gegen soetwas gefeit...
Grundsätzlich baut aber FastReport Mist, denn Umlaute haben -soweit ich weiss- in XML nix zu suchen.
_________________ Na denn, dann. Bis dann, denn.
|
|
|