Autor Beitrag
mexx
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: Fr 13.04.07 16:02 
Ich verwende die FastReport-Komponenten und speichere einen Report wie folgt in einen Blob-Feld einer FireBird-Datenbank.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: Fr 13.04.07 16:31 
user profile iconmexx 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: 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.

ausblenden 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); //entweder passiert hier ein Fehler mit dem Blobinhalten
  
 QueryInsertReport.ParamByName('FastReport').LoadFromStream(MemStream,ftBlob); //oder hier werden die Inhalte verändert 
... 
end;

_________________
Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: Mo 16.04.07 08:20 
user profile iconalzaimar 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mo 16.04.07 08:50 
Such mal nach HexToBin und BinToHex in der Classes-Unit.

Generell sollte es so klappen:
ausblenden 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);         // 1 Byte => 2 Char im HEX-Format.
  P := PChar (sFastReport Memory);                 // Memory zeigt auf das 1.Zeichen des FastReport-Streams
  BinToHex (P, PChar (Result), sFRT.Size); 
End;

Procedure StringToFastReportStream (aString : String; sFastReport : TMemoryStream);
Var
  p : PChar;

Begin
  sFastReport.Size := Length (aString) div 2;      // 2 HEX-Char => 1 Byte im Stream
  P := PChar (sFastReport Memory);             
  HexToBin (PChar (aString), P, Length (aString)); // Nun zurück konvertieren
End;

Ist ungetestet, sollte aber funktionieren.

_________________
Na denn, dann. Bis dann, denn.
mexx Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: Mo 16.04.07 09:18 
Ich hab es wie folgt.

Lesen
ausblenden 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
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: 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.

ausblenden 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)); // Hexcode in Bincode

 //Hier müsste nun die Variable P in ein Stream gewandelt werden aber wie?

 Result := ???
   End;

_________________
Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
mexx Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: Mo 16.04.07 11:41 
ausblenden Delphi-Quelltext
1:
Result.Write(P,Length(P));					


:?: :D :?:

_________________
Das Unsympathische an den Computern ist, dass sie nur ja oder nein sagen können, aber nicht vielleicht.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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:
ausblenden 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...

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1183



BeitragVerfasst: 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
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:
...
 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
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:
...
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);   // Stream to String
    sFastReport.Size := Length (aString) div 2;      // 2 HEX-Char => 1 Byte im Stream
    P := PChar (sFastReport);
    HexToBin (PChar (aString), P, Length (aString)); // von Hex zu Bin zurück
    Result.Write(P,Length(P));                       // String to Stream
   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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: 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:
ausblenden Delphi-Quelltext
1:
Result.Write(P^,Length(P));					


Gruß Horst
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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.

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:
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 8shl 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:
ausblenden 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;      // 2 HEX-Char => 1 Byte im Stream
  P := PChar (sFastReport Memory);             
  HexToBin (PChar (aString), P, Length (aString)); // Nun zurück konvertieren
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.