I have problem with reading blob field from database which contains msword file and save it into file (.doc/.docx). What is moree this works great in Delphi 2010 but in Delphi Xe2 saved files are invalid.This is my code
dane.SQLtmp.Close;
dane.SQLtmp.SQL.Clear;
dane.SQLtmp.SQL.Add('select wydruk,typ,IdWydruku from wydruki where nazwa=:d0');
dane.SQLtmp.Params[0].AsString:=name;
dane.SQLtmp.Open;
if dane.SQLtmp.RecordCount> 0 then
begin
t:=TMemoryStream.Create;
t.Position:=0;
TblobField(dane.sqltmp.FieldByName('wydruk')).saveToStream(T);
T.SaveToFile('C:\FILE'+filetpe);
t.Free;
end;
Saving file into database:
dane.SQLtmp.Close;
dane.SQLtmp.SQL.Clear;
dane.SQLtmp.SQL.Add('insert into Wydruki (Nazwa,Operator,wydruk,opis,typ,rodzaj,podmiot,typsplaty,grupa,podgrupa)');
dane.Sqltmp.SQL.Add('VALUES (:d0,:d1,:d2,:d3,:d4,:d5,:d6,:d7,:d8,:d9)');
dane.SQLtmp.Params[0].AsString:=NazwaPliku; //File name
dane.SQLtmp.Params[1].AsInteger:=glowny.ID_operator;
t:=TMemoryStream.Create;
t.Position:=0;
t.LoadFromFile(OpenFile.FileName);
t.Position:=0;
dane.sqltmp.Params[2].LoadFromStream(t,ftBlob);
dane.SQLtmp.Params[3].AsString:=opis;
dane.SQLtmp.Params[4].AsString:=typ; // file type
// .
// .
// .
dane.SQLtmp.ExecSQL;
In Delphi 2010 it worked... :/
You need to use TBlobField.CreateBlobStream and copy to a TFileStream.
According to the documentation:
Call CreateBlobStream to obtain a stream for reading and writing the value of the field specified by the Field parameter. The Mode parameter indicates whether the stream will be used for reading the field's value (bmRead), writing the field's value (bmWrite), or modifying the field's value (bmReadWrite).
The Tip on the same documentation page says:
Tip: It is preferable to call CreateBlobStream rather than creating a blob stream directly in code. This ensures that the stream is appropriate to the dataset, and may also ensure that datasets that do not always store BLOB data in memory fetch the blob data before creating the stream.
Sample code based on yours above:
var
Blob: TStream;
Strm: TFileStream;
BlobFld: TBlobField;
begin
dane.SQLtmp.SQL.Text := 'select wydruk,typ,IdWydruku from wydruki where nazwa=:d0';
dane.SQLtmp.Params[0].AsString:=name;
dane.SQLtmp.Open;
BlobFld := dane.SQLtmp.FieldByName('wydruk') as TBlobField;
Blob := dane.SQLtmp.CreateBlobStream(BlobFld, bmRead);
try
Strm := TFileStream.Create('C:\FILE' + filetpe, fmCreate);
try
Strm.CopyFrom(Blob, Blob.Size);
finally
Strm.Free;
end;
finally
Blob.Free;
end;
end;
The problem was in Interbase components (IB) in Xe2. When I changed them to FireDac'c components my and Yours code works.
That's interesting, recently embarcadero's product have many bugs.
You can do this
query.SQL.Add('SELECT * FROM something');
query.Open;
query.FieldByName('file') as TBlobField).SaveToFile(SaveDialog1.FileName);
Related
I'm trying to work out whether I can persist the data stored in a TFDMemTable after closing the dataset without having to save it to a file.
I checked the TResourceOptions.Persistent but this will only save to the file name specified in TResourceOptions.PersistentFileName at runtime. You can save data at design time in the dfm if you leave the filename blank, but this isn't useful.
I also looked at the .SaveToStream/LoadFromStream but again that only saves/loads to a file specified in TResourceOptions.PersistentFileName, I was hoping I could just keep it in a local memory stream.
I have the DevExpress components which I know theirs can persist the data, but I'm trying to use the FDAC REST examples which have built in functionality for transferring the tables as JSON.
Am I missing a setting somewhere that will allow me to persist the data, or does anyone have a method to do it?
The following works fine for me:
procedure TForm1.Button5Click(Sender: TObject);
var
MS : TMemoryStream;
begin
// Requires TFDStanStorageBinLink on form/datamodule
MS := TMemoryStream.Create;
try
FDMemTable1.SaveToStream(MS);
FDMemTable1.Close;
// sometime later
MS.Position := 0;
FDMemTable1.LoadFromStream(MS);
finally
MS.Free;
end;
end;
Am trying to create an ini file to save the an application configuration.
the saving part works perfect with the input from the edit boxes 1,2,3 etc here is the ini sample
[1server]
SSHHost=ssh.com
SSHPort=443
Username=user
Password=123
[2server]
SSHHost=ssh.com
SSHPort=443
Username=user
Password=123
[ProxySettings]
Proxy=127.0.0.1
Port=8080
Type=http
how do i make the app read the saved ini setting on launching it and is it possible to hide or encrypt user saved password?
Simply read the Ini file in your main form's FormCreate event.
procedure TForm1.FormCreate(Sender: TObject);
var
Ini: TIniFile;
begin
Ini := TIniFile.Create(YourIniFileName);
try
// The final parameter to all of the `ReadXx` functions is a default
// value to use if the value doesn't exist.
Edit1.Text := Ini.ReadString('1server', 'SSHHost', 'No host found');
Edit2.Text := Ini.ReadString('1server', 'SSHPort', 'No port found');
// Repeat, using ReadString, ReadInteger, ReadBoolean, etc.
finally
Ini.Free;
end;
end;
One word of caution: TIniFile has known issues with writing to network locations, so if there's any chance of that you should use TMemIniFile instead. TIniFile wraps the WinAPI INI support functions (ReadPrivateProfileString and others), while TMemIniFile is written totally in Delphi code and doesn't suffer from the same problems. They're syntax-compatible and in the same unit, so it's a simple matter of changing TIniFile to TMemIniFile in your variable declaration and the line that creates the Ini:
var
Ini: TMemIniFile;
begin
Ini := TMemIniFile.Create(YourIniFileName);
...
end;
As far as encrypting the password, you can use any encryption algorithm you want, as long as the encrypted value can be converted to a textual representation. (Ini files don't handle binary values.) The choice of algorithm is up to you based on the level of security you're attempting to achieve.
I have problem with reading blob field from database which contains msword file and save it into file (.doc/.docx). What is moree this works great in Delphi 2010 but in Delphi Xe2 saved files are invalid.This is my code
dane.SQLtmp.Close;
dane.SQLtmp.SQL.Clear;
dane.SQLtmp.SQL.Add('select wydruk,typ,IdWydruku from wydruki where nazwa=:d0');
dane.SQLtmp.Params[0].AsString:=name;
dane.SQLtmp.Open;
if dane.SQLtmp.RecordCount> 0 then
begin
t:=TMemoryStream.Create;
t.Position:=0;
TblobField(dane.sqltmp.FieldByName('wydruk')).saveToStream(T);
T.SaveToFile('C:\FILE'+filetpe);
t.Free;
end;
Saving file into database:
dane.SQLtmp.Close;
dane.SQLtmp.SQL.Clear;
dane.SQLtmp.SQL.Add('insert into Wydruki (Nazwa,Operator,wydruk,opis,typ,rodzaj,podmiot,typsplaty,grupa,podgrupa)');
dane.Sqltmp.SQL.Add('VALUES (:d0,:d1,:d2,:d3,:d4,:d5,:d6,:d7,:d8,:d9)');
dane.SQLtmp.Params[0].AsString:=NazwaPliku; //File name
dane.SQLtmp.Params[1].AsInteger:=glowny.ID_operator;
t:=TMemoryStream.Create;
t.Position:=0;
t.LoadFromFile(OpenFile.FileName);
t.Position:=0;
dane.sqltmp.Params[2].LoadFromStream(t,ftBlob);
dane.SQLtmp.Params[3].AsString:=opis;
dane.SQLtmp.Params[4].AsString:=typ; // file type
// .
// .
// .
dane.SQLtmp.ExecSQL;
In Delphi 2010 it worked... :/
You need to use TBlobField.CreateBlobStream and copy to a TFileStream.
According to the documentation:
Call CreateBlobStream to obtain a stream for reading and writing the value of the field specified by the Field parameter. The Mode parameter indicates whether the stream will be used for reading the field's value (bmRead), writing the field's value (bmWrite), or modifying the field's value (bmReadWrite).
The Tip on the same documentation page says:
Tip: It is preferable to call CreateBlobStream rather than creating a blob stream directly in code. This ensures that the stream is appropriate to the dataset, and may also ensure that datasets that do not always store BLOB data in memory fetch the blob data before creating the stream.
Sample code based on yours above:
var
Blob: TStream;
Strm: TFileStream;
BlobFld: TBlobField;
begin
dane.SQLtmp.SQL.Text := 'select wydruk,typ,IdWydruku from wydruki where nazwa=:d0';
dane.SQLtmp.Params[0].AsString:=name;
dane.SQLtmp.Open;
BlobFld := dane.SQLtmp.FieldByName('wydruk') as TBlobField;
Blob := dane.SQLtmp.CreateBlobStream(BlobFld, bmRead);
try
Strm := TFileStream.Create('C:\FILE' + filetpe, fmCreate);
try
Strm.CopyFrom(Blob, Blob.Size);
finally
Strm.Free;
end;
finally
Blob.Free;
end;
end;
The problem was in Interbase components (IB) in Xe2. When I changed them to FireDac'c components my and Yours code works.
That's interesting, recently embarcadero's product have many bugs.
You can do this
query.SQL.Add('SELECT * FROM something');
query.Open;
query.FieldByName('file') as TBlobField).SaveToFile(SaveDialog1.FileName);
i am downloading a file from my server (i only get the bytes and a DateTime for the lastwritetime attribute) and after downloading the data i create a new file on my local machine and want to set the lastwritetime attribute.
For this i am using the following method:
procedure SetFileDate(const FileName: string; NewDate: TDateTime);
var
FileDate, FileHandle: Integer;
begin
try
FileDate := DateTimeToFileDate(NewDate);
FileHandle := FileOpen(FileName, fmOpenReadWrite or fmShareDenyWrite);
if FileHandle > 0 then
begin
FileSetDate(FileHandle, FileDate);
FileClose(FileHandle);
end;
except
begin
// ERROR Log
err.Msg('FileReqThrd.SetFileDate');
end;
end;
end;
For the 'NewDate' parameter i use the DateTime which i get from my server.
I tried to convert the DateTime from the server like this to get the valid lastwritetime (i am requesting the data from a WCF this is why i am converting it to UTCDateTime, the untouched data from the WCF service is TXSDateTime):
TDateTime cloudFileDateTime := StrToDateTime(DateTimeToStr(cloudDownloadResult.FileCloudData.Lastwritetime.AsUTCDateTime));
But in the end my lastwritetime attribute from files which have a lastwritetime in the wintertime period are wrong with -1h.
I hope you understand my problem and can give me an idea how to solve it.
Best regards
The easiest way to do this is to call TFile.SetLastWriteTimeUtc from the System.IOUtils unit.
TFile.SetLastWriteTimeUtc(FileName,
DateTimeUtc);
If this function is not available use the Win32 API function SetFileTime.
You'll also need DateTimeToSystemTime and then SystemTimeToFileTime in that scenario.
The answer provided by David (to use TFile.SetLastWriteTimeUtc) is correct. However, there was some discussion in the comments about bugs. As I am unable to comment (due to lack of rep), I'll add this here for anyone who comes across this problem in future.
While TFile.SetLastWriteTimeUtc works correctly, TFile.GetLastWriteTimeUtc does indeed have a bug relating to daylight saving time. There is a bug report filed with Embarcadero, and it looks like they've now fixed it in Delphi 10.3 Rio (though I haven't tried it yet).
If you are working with an older version of Delphi, you will have to work around the problem via use of the Windows API. e.g. GetFileAttributesEx:
function GetFileModTimeUtc(filePath: string): TDateTime;
var data: TWin32FindData;
var sysTime: TSystemTime;
begin
if GetFileAttributesEx(PChar(filePath), GetFileExInfoStandard, #data) and
FileTimeToSystemTime(data.ftLastWriteTime, sysTime) then begin
Result := SystemTimeToDateTime(sysTime);
end else begin
raise Exception.Create('Unable to get last file write time for ' + filePath);
end;
end;
could anyone help?
I've inherited some software written in Delphi 5 which allows member data and fields from a database (.ADT file) to be used merged in to word.
It works fine with all version of Word except 2010 where it won't load any documents and shows the error:
"That Method is not available on that object"
I have been told the solution is to replace the preset components OpWord and OpDataSet with Ole variants. I have done so with OpWord using:
wrdApp := CreateOleObject('Word.Application');
and the documents now load up but without any merge field data. Can anyone let me know how to extract this data from the database, as the OpDataSet seems to simply just point at the table?
Or can anyone suggest a better solution than the one I'm trying. I'm very new to Delphi so I'm in abit over my head
Edit: (Requested Info)
Sorry I have more details and code if required.
The components appear to belong to a library called OfficePartner along with TOpExcel,TOpOutlook and others.
The .doc is selected from a popup ListPane on Form30, opened and populated with merge field data from Table 4. Table 1 is the members database:
{Use Table4 as we can Set a range on it}
Table4.SetRange([Table1.FieldByName('Member Id').AsString],[Table1.FieldByName('Member Id').AsString]);
{Open Word}
OpWord1.Connected := True;
{Open the Test Document}
OpWord1.OpenDocument(DocumentDirectory + '\' + Form30.ListBox1.Items[Form30.ListBox1.ItemIndex]);
{Populate the Test Document}
OpWord1.ActiveDocument.MailMerge.OfficeModel := OpDataSetModel1;
OpWord1.ActiveDocument.PopulateMailMerge;
OpWord1.ActiveDocument.ExecuteMailMerge;
I hope this helps...
Here is a little procedure for word mail merge that I used way back for D6, it's a just snippet and you have to include in some class, I don't have Delphi anymore so can't compile to make sure that it works, anyway here it is, hope it helps:
procedure MailMergeWord;
var
WordApp: TWordApplication;
WordDoc: TWordDocument;
doc : WordDocument;
FileName: OleVariant;
xx: integer;
begin
WordApp := TWordApplication.Create(nil);
WordApp.ConnectKind := ckNewInstance;
WordDoc := TWordDocument.Create(WordApp);
FileName := 'TemplateDoc.doc';
doc := WordApp.Documents.Open(FileName,EmptyParam,EmptyParam,EmptyParam,EmptyParam
,EmptyParam,EmptyParam,EmptyParam,EmptyParam
,EmptyParam);
WordDoc.ConnectTo(Doc);
for xx := 1 to WordDoc.Fields.Count do
WordDoc.Fields.Item(xx).Result.Text := OnWordVariable(WordDoc.Fields.Item(xx).Code.Text);
WordDoc.PrintOut;
WordDoc.Free;
WordApp.Free;
end;
function OnWordVariable(varName: string): string;
begin
Result := 'Value based on variable name';
end;