I have an application for registration which saves customer information in a file that is a file for each client, using
Write(myFile, customer);
CloseFile(myFile);
FileMode := fmOpenReadWrite;
But I need to attach a picture [jpg] of the customer and puts it into the file, does anyone have any idea how can I do this?
This a complete List os records
type
TCustomer = Record
NomeCompleto : string[100];
Nome : string[20];
Sobrenome : string[20];
Idade : string[20];
Sexo : string[20];
Escolaridade:string[60];
CPF: string[11];
RG:string[20];
EstadoCivil:string[20];
Filhos: boolean;
QTFilhos: string[10];
Foto:string[255];
Endereco:string[40];
Numero: string[20];
Bairro: string[20];
Cidade:string[20];
Estado:string[2];
Telefone:string[10];
Celular:string[10];
Email:string[40];
Adicionais: string[200];
Objetivo: string[200];
Experiencia1: string[45];
Entrada1: string[4];
Saida1: string[4];
Cargo1: string[35];
resumo1: string[200];
Experiencia2: string[45];
Entrada2: string[4];
Saida2: string[4];
Cargo2: string[35];
resumo2: string[200];
Experiencia3: string[45];
Entrada3: string[4];
Saida3: string[4];
Cargo3: string[35];
resumo3: string[200];
Experiencia4: string[45];
Entrada4: string[4];
Saida4: string[4];
Cargo4: string[35];
resumo4: string[200];
Instituicao1:string[45];
Nomecurso1:string[45];
datainicial1:string[45];
datafinal1:string[45];
Instituicao2:string[45];
Nomecurso2:string[45];
datainicial2:string[45];
datafinal2:string[45];
Instituicao3:string[45];
Nomecurso3:string[45];
datainicial3:string[45];
datafinal3:string[45];
Instituicao4:string[45];
Nomecurso4:string[45];
datainicial4:string[45];
datafinal4:string[45];
Instituicao5:string[45];
Nomecurso5:string[45];
datainicial5:string[45];
datafinal5:string[45];
Instituicao6:string[45];
Nomecurso6:string[45];
datainicial6:string[45];
datafinal6:string[45];
instituicao:string[45];
area:string[45];
ano:string[10];
carga1:string[10];
carga2:string[10];
carga3:string[10];
carga4:string[10];
carga5:string[10];
carga6:string[10];
personalidade:string[255];
Stop using old-style Pascal file I/O and embrace file streams. Write your file as a binary file, not a text file. Then you can do something like the following at a minimum.
To create the file:
var
customer: TCustomer;
jpg: TJPEGImage;
myFile: TFileStream;
begin
jpg := TJPEGImage.Create;
try
// fill customer and jpg as needed...
myFile := TFileStream.Create(Filename, fmCreate);
try
myFile.WriteBuffer(customer, sizeof(customer));
jpg.SaveToStream(myFile);
finally
myFile.Free;
end;
finally
jpg.Free;
end;
end;
To load the file:
var
customer: TCustomer;
jpg: TJPEGImage;
myFile: TFileStream;
begin
jpg := TJPEGImage.Create;
try
myFile := TFileStream.Create(Filename, fmOpenRead);
try
myFile.ReadBuffer(customer, sizeof(customer));
jpg.LoadFromStream(myFile);
finally
myFile.Free;
end;
// use customer and jpg as needed...
finally
jpg.Free;
end;
end;
Given that your customer record contains fixed sized items, I'd suggest defining something like:
photo : byte[20000];
You can then open the JPG file as a file of byte, read all of it in, and store that in the photo array in your record.
Of course this has the downside that you will have to decide upfront what the maximum image size will be, but for a small face photo, 20-50kB should be more than enough.
It is also possible to reopen the file as a file of type byte, and simply append the binary image data to the end (ie, read the image data in as a byte array or sequence of bytes, and copy/append that to the customer data file), provided your customer record (as it is now) is of a fixed size. This way, you know the 'balance' of your data file is pure image data.
Related
I want to compress files into Zip in-memory (I will store the result on a database instead of creating files in the file system).
How can I read the raw content for the compressed Zip file ?. I can't see any property to read that content, or any method to save that content into an Stream or any other in-memory structure.
function GetZip(UncompressedFile: TStream): TBytes;
var AZipFile: TZipFile;
begin
AZipFile := TZipFile.Create;
try
AZipFile.Add(UncompressedFile);
Result := AZipFile.Data; // ?? How to get the compressed file without saving it to the file system ??
finally
AZipfile.Free;
end;
end;
Thank you.
Thanks to AmigoJack and Remy Lebeau for letting me know that I can use the Zip input Stream to also get the result.
This works fine :
function Zip_AddFile(FileToAdd: TStream; Title: string): TBytes; overload;
begin
Result := Zip_AddFile([], FileToAdd, Title);
end;
function Zip_AddFile(Zip: TBytes; FileToAdd: TStream; Title: string): TBytes; overload;
var AZipFile: TZipFile;
ZipStream: TBytesStream;
begin
ZipStream := TBytesStream.Create(Zip);
AZipFile := TZipFile.Create;
try
AZipFile.Open(ZipStream, zmReadWrite);
AZipFile.Add(FileToAdd, Title);
AZipFile.Close;
Result := ZipStream.Bytes;
finally
AZipfile.Free;
ZipStream.Free;
end;
end;
I am trying to use the system.filesize function to get the size of a file in delphi, it works ok for files < 4GB but fails for files > 4GB.
so i implemented my own that opens the required file as a filestream and gets the streamsize which works perfectly.
Here is a Snippet
function GiveMeSize(PathtoFile : string): int64;
var
stream : TFileStream;
size : int64;
begin
try
stream := TFileStream.Create(PathtoFile, fmOpenReadWrite or fmShareDenyNone);
size := stream.size;
except
showmessage('Unable to get FileSize');
end
finally
stream.free;
end;
but the problem with my above function is that it opens the file which incurs some overhead when processing a large number of files.
is there any function that can get filesize of files > 4GB without opening the file first?
I have tried some functions online but they tend to report wrong file size for files greater than 4GB.
Delphi Version : XE5
Thanks.
System.FileSize is a Pascal I/O function that operates on Pascal File variables. If you want to get the size of a file specified by path, then System.FileSize is simply wrong function to use.
What's more, you quite likely don't want to open the file just to obtain its size. I obtain the file size like this:
function FileSize(const FileName: string): Int64;
var
AttributeData: TWin32FileAttributeData;
begin
if GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, #AttributeData) then
begin
Int64Rec(Result).Lo := AttributeData.nFileSizeLow;
Int64Rec(Result).Hi := AttributeData.nFileSizeHigh;
end
else
Result := -1;
end;
Googling for the keywords "delphi get file size int64" gives you plenty of examples
I use this:
function GetSizeOfFile(const Filename: string): Int64;
var
sr : TSearchRec;
begin
if FindFirst(fileName, faAnyFile, sr ) <> 0 then
Exit(-1);
try
result := Int64(sr.FindData.nFileSizeHigh) shl Int64(32) + Int64(sr.FindData.nFileSizeLow);
finally
System.SysUtils.FindClose(sr) ;
end;
end;
You can avoid bit-shifting by assigning into a variant record which I think makes the code below more efficient.
function GetSizeOfFile(const Filename: string): Int64;
type
TSizeType = (stDWORD, stInt64);
var
sizerec: packed record
case TSizeType of
stDWORD: (SizeLow: LongWord; SizeHigh: LongWord);
stInt64: (Size: Int64);
end;
sr : TSearchRec;
begin
if FindFirst(fileName, faAnyFile, sr ) <> 0 then
begin
Result := -1;
Exit;
end;
try
sizerec.SizeLow := sr.FindData.nFileSizeLow;
sizerec.SizeHigh := sr.FindData.nFileSizeHigh;
Result := sizerec.Size;
finally
SysUtils.FindClose(sr) ;
end;
end;
I could've just used "case Boolean of" but like to use the power of Pascal to make the code more descriptive.
Hello please i've this packed record :
type
TMyRecord = packed record
BufSize: Word;
TargetUser:array[0..80] of char;
StreamHolder: Byte;
end;
PMyRecord = ^TMyRecord;
// i would like to save the MemoryStream into the StreamHolder
please see my below procedure:
Procedure AddToRec(ATargetUser:String);
var
MyRecord: PMyRecord;
Strm:TMemoryStream;
Size: Integer;
begin
Strm:=TMemoryStream.Create;
try
Strm.LoadFromFile('myFile.dat');
Strm.position:=0;
Size:=Strm.size;
GetMem(MyRecord,Size);
ZeroMemory(MyRecord,Size);
MyRecord.BufSize := Size;
StrCopy(MyRecord.TargetUser,PChar(ATargetUser));
// here how could i copy the Strm into the StreamHolder ?
//SendMyBuffer(MyRecord,Size);
finally
Strm.free;
end;
end;
So please how could i copy the Strm to the StreamHolder ?
many thanks
You appear to want to copy the entire stream onto #MyRecord.StreamHolder. Do that like this:
Strm.ReadBuffer(MyRecord.StreamHolder, Size);
You'll also need to change your GetMem to allocate enough memory.
GetMem(MyRecord, Size + SizeOf(MyRecord^) - SizeOf(MyRecord.StreamHolder));
Or perhaps more elegantly:
GetMem(MyRecord, Size + Integer(#PMyRecord(nil)^.StreamHolder));
As it stands your code does not take account of that part of the record which appears before StreamHolder.
Why not holding
StreamHolder: Byte;
as
StreamHolder: tMemoryStream;
and change the procedure to
var
MyRecord: PMyRecord;
begin
GetMem(MyRecord,SizeOf(pMyRecord));
myRecord.StreamHolder := TMemoryStream.Create;
try
myRecord.StreamHolder.LoadFromFile('myFile.dat');
//Strm.position:=0;
//Size:=Strm.size;
//ZeroMemory(MyRecord,Size);
//MyRecord.BufSize := Size;
StrCopy(MyRecord.TargetUser,PChar(ATargetUser));
finally
// no free in here... free the streamholder whenever you get rid of MyRecord...
end ;
I used Binary to Base64 function that you answered :
Binary to Base64 (Delphi)
I successfully encode a file to base64 string and write it to MsSQL2008 database, but i want to ask a question:
How can i write this file to disk again with using EncdDecd.pas?
As always, David answered sufficiently. Although I can't resist to give a slightly different solution using some of the goodies from the recent Delphi versions.
procedure DecodeFile(const base64: AnsiString; const FileName: string);
var
stream: TBytesStream;
begin
stream := TBytesStream.Create(DecodeBase64(base64));
try
stream.SaveToFile(Filename);
finally
stream.Free;
end;
end;
This function will take a base64 encoded string, decode it, and write the resulting byte array to a file.
procedure DecodeToFile(const base64: AnsiString; const FileName: string);
var
stream: TFileStream;
bytes: TBytes;
begin
bytes := DecodeBase64(base64);
stream := TFileStream.Create(FileName, fmCreate);
try
if bytes<>nil then
stream.Write(bytes[0], Length(Bytes));
finally
stream.Free;
end;
end;
To explain what is happening here, the first line
bytes := DecodeBase64(base64);
performs the decode and returns the decoded binary contents of the file in a TBytes variable. TBytes is simply an array of bytes.
The next step is to create the file. The idiomatic way to write files in Delphi is to use streams. In this case we want a TFileStream.
stream := TFileStream.Create(FileName, fmCreate);
The fmCreate option means that if the file already exists, it will be replaced and overwritten by what we write.
The final step is to write the contents of the byte array to the file
if bytes<>nil then
stream.Write(bytes[0], Length(Bytes));
The if bytes<>nil check is to handle the case where the base64 string decodes to an empty array. If we were to remove that check then the following line would result in a runtime error if you were running with range checking enabled (which you should be doing). The call to stream.Write should be self-explanatory.
After looking into Soap.EncdDecd the one can find more platform independent way, as it's DecodeBase64 uses universal (no AnsiString) methods from System.NetEncoding.
Based on Uwe's sample:
uses
...
System.Classes,
System.NetEncoding;
...
procedure DecodeFile(const base64: String; const FileName: string);
var
stream: TBytesStream;
begin
stream := TBytesStream.Create(TNetEncoding.Base64.DecodeStringToBytes(base64));
try
stream.SaveToFile(Filename);
finally
stream.Free;
end;
end;
uses
Soap.EncdDecd;
function TForm1.EncodeFile(const FileName: string): AnsiString;
var
MemStream: TMemoryStream;
begin
MemStream := TMemoryStream.Create;
try
MemStream.LoadFromFile(Filename);
Result := EncodeBase64(MemStream.Memory, MemStream.Size);
finally
MemStream.Free;
end;
end;
function TForm1.DecodeFile(const base64: AnsiString): TBytesStream;
begin
Result := TBytesStream.Create(DecodeBase64(base64));
end;
I have a very old Delphi2006(v10.0.2558.35231 Update 2) and had to decode base64 UTF8 encoded input strings. I finally figured it out and heres an example for anyone interested.
Uses
IdCoderMIME; // Indy9
var
decoder: TIdDecoderMIME;
str: WideString;
- - -
decoder := TIdDecoderMIME.Create(nil);
str := base64DecodeUTF8(decoder, b64sourcestr);
decoder.Free;
- - -
function base64DecodeUTF8(decoder:TIdDecoderMIME; str:String): WideString;
var
stream:TMemoryStream;
utf8: UTF8String;
//idx:Integer;
begin
stream := TMemoryStream.Create;
try
decoder.DecodeToStream(str, stream);
setString(utf8, PChar(stream.Memory), stream.Size);
Result := UTF8Decode(utf8);
//for idx := 0 to stream.Size-1 do begin
// Writeln(PChar(stream.Memory)[idx] + ' ' + IntToStr(ORD(PChar(stream.Memory) [idx])) );
//end;
finally
stream.Free;
end;
end;
For some reason my OpenID account no longer exists even when I used it yesterday. But anyway.
I need to save record data into a .dat file. I tried a lot of searching, but it was all related to databases and BLOB things. I wasn't able to construct anything from it.
I have the following record
type
Scores = record
name: string[50];
score: integer;
end;
var rank: array[1..3] of scores;
I just need a simple way of saving and reading the record data from a .dat file. I had the book on how to do it, but that's at school.
You should also take a look at the file of-method.
This is kinda out-dated, but it's a nice way to learn how to work with files.
Since records with dynamic arrays (including ordinary strings) can't be stored to files with this method, unicode strings will not be supported. But string[50] is based on ShortStrings and your record is therefore already non-unicode...
Write to file
var
i: Integer;
myFile: File of TScores;
begin
AssignFile(myFile,'Rank.dat');
Rewrite(myFile);
try
for i := 1 to 3 do
Write(myFile, Rank[i]);
finally
CloseFile(myFile);
end;
end;
Read from file
var
i: Integer;
Scores: TScores;
myFile: File of TScores;
begin
AssignFile(myFile, 'Rank.dat');
Reset(myFile);
try
i := 1;
while not EOF(myFile) do
begin
Read(myFile, Scores);
Rank[i] := Scores; //You will get an error if i is out of the array bounds. I.e. more than 3
Inc(i);
end;
finally
CloseFile(myFile);
end;
end;
Use streams. Here is a simple demo (just demo - in practice there is no need to reopen file stream every time):
type
Scores = record
name: string[50];
score: integer;
end;
var rank: array[1..3] of scores;
procedure WriteScores(var Buf; Count: Integer);
var
Stream: TStream;
begin
Stream:= TFileStream.Create('test.dat', fmCreate);
try
Stream.WriteBuffer(Buf, SizeOf(Scores) * Count);
finally
Stream.Free;
end;
end;
procedure ReadScore(var Buf; Index: Integer);
var
Stream: TStream;
begin
Stream:= TFileStream.Create('test.dat', fmOpenRead or fmShareDenyWrite);
try
Stream.Position:= Index * SizeOf(Scores);
Stream.ReadBuffer(Buf, SizeOf(Scores));
finally
Stream.Free;
end;
end;
// write rank[1..3] to test.dat
procedure TForm1.Button1Click(Sender: TObject);
begin
rank[2].name:= '123';
WriteScores(rank, Length(Rank));
end;
// read rank[2] from test.dat
procedure TForm1.Button2Click(Sender: TObject);
begin
rank[2].name:= '';
ReadScore(rank[2], 2 - Low(rank));
ShowMessage(rank[2].name);
end;
Look in the help under "blockread" and or "blockwrite". There probably will be an example