Title: Storing data into a stream and reading it back.
Question: I've posted this question before with little to no results. However, if you want to be able to add files & record-structures into a single file - here is one of three examples I came up with.
Answer:
TempRec = record
mFullName:String[25];
mSalary:String[10];
mDept:String[25];
end;
var
Form1: TForm1;
MyData:TempRec;
jpg:TJpegImage;
St:TMemoryStream;
S1:TStream;
implementation
{$R *.dfm}
uses Jpeg;
................................
procedure TForm1.SpeedButton1Click(Sender: TObject);
var BS,FS:TStream;
sl:TStringList;// Create an index-table?
Bm:TBookMark;
begin
FFileName:=ExtractFilePath(Application.ExeName)+'DATA.DBM';
FS:=TFileStream.Create(FFileName,fmCreate or fmOpenRead); // Keep this file open...
Bm:=Query3.GetBookmark;
Query3.First;
Query3.DisableControls;
sl:=TStringList.Create;
While Not Query3.Eof do // Loop it...
begin
BS:=Query3.CreateBlobStream(Query3.FieldByName('EmpPict') as TBlobField, bmRead);
try
sl.Add(IntToStr(FS.Position)); //!! Store the positions to file...
MyData.mFullName:=Query3.FieldByName('FullName').AsString;
MyData.mSalary:=Query3.FieldByName('Salary').AsString;
MyData.mDept:=Query3.FieldByName('Dept').AsString;
FS.Write(MyData.mFullName,SizeOf(Mydata.mFullName));
FS.Write(MyData.mSalary,SizeOf(Mydata.mSalary));
FS.Write(MyData.mDept,SizeOf(Mydata.mDept));
FS.CopyFrom(BS,BS.Size); // Copy the Blob data
finally
BS.Free;// Free blob!!!
Query3.Next;
end;
sl.SaveToFile(ChangeFileExt(FFileName,'.MDX')); // Our indexes...
end;
sl.Free;
FS.Free;
Query3.GotoBookmark(Bm);
Query3.FreeBookmark(Bm);
Query3.EnableControls;
end;
// The program that reads and displays
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls,Jpeg, ComCtrls, Buttons;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Panel1: TPanel;
Image1: TImage;
ListBox2: TListBox;
Label1: TLabel;
Label2: TLabel;
bFirst: TSpeedButton;
bPrev: TSpeedButton;
bNext: TSpeedButton;
bLast: TSpeedButton;
OpenDialog1: TOpenDialog;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
cmdLoad: TSpeedButton;
procedure ListBox2Click(Sender: TObject);
procedure bLastClick(Sender: TObject);
procedure bFirstClick(Sender: TObject);
procedure bNextClick(Sender: TObject);
procedure bPrevClick(Sender: TObject);
procedure cmdLoadClick(Sender: TObject);
private
{ Private declarations }
Procedure UpdateButtons;
public
{ Public declarations }
end;
TempRec = record
mFullName:String[25];
mSalary:String[10];
mDept:String[25];
end;
var
Form1: TForm1;
FS:TStream;
Data:TStream;
jpg:TJpegImage;
NumRecs:Integer;
MyData:TempRec;
implementation
var FileName:string;
{$R *.dfm}
Procedure TForm1.UpdateButtons;
begin
if ListBox2.Items.Count = 1 then
begin
ListBox2.Selected[0]:=True;
ListBox2.OnClick(NIL);
bNext.Enabled:=False;
bFirst.Enabled:=False;
bPrev.Enabled:=False;
bLast.Enabled:=False;
end
else
begin
ListBox2.Selected[0]:=True;
ListBox2.OnClick(NIL);
bNext.Enabled:=True;
bFirst.Enabled:=True;
bPrev.Enabled:=True;
bLast.Enabled:=True;
end;
end;
procedure TForm1.ListBox2Click(Sender: TObject);
begin
{ Just a little position filtering...}
try
StrToInt(ListBox2.Items[ListBox2.ItemIndex]);
Except
Exit;
end;
Data:=TMemoryStream.Create;
jpg:=TJpegImage.Create;
FS:=TFileStream.Create(FileName,fmOpenRead);
try
{ Add the Jpeg Image from our free blob into the "Data Stream".}
Data.CopyFrom(FS,FS.Size);
{ Find the position the (Data Stream) and go to it.
No need to worrie about reading pass the Stream; We have the exact position!}
Data.Seek(StrToInt(listBox2.Items[ListBox2.ItemIndex]),soFromBeginning);
{ Our TempRec size only consist of 63~ bytes; you should use (SizeOF() instead...}
Data.Read(MyData.mFullName,25);
Data.Read(MyData.mSalary,10);
Data.Read(MyData.mDept,25);
Edit1.Text:=MyData.mFullName;
Edit2.Text:=MyData.mSalary;
Edit3.Text:=MyData.mDept;
{ Read beyond the 63 or so bytes and locate the Jpeg Image...}
Data.Seek( StrToInt(listBox2.Items[ListBox2.ItemIndex]) + 60 ,soFromBeginning);
if Data nil then
begin
try
jpg.LoadFromStream(Data);
Image1.Picture.Assign(jpg);
Except
Image1.Picture :=nil;
end;
end;
finally
FS.Free;
jpg.Free;
Data.Free;
end;
{ Update the UI...}
Label1.Caption:=Format('Record %d of %d',[ListBox2.ItemIndex + 1,NumRecs]);
if ListBox2.Selected[0] =True then
begin
bNext.Enabled:=True;
bLast.Enabled:=True;
bFirst.Enabled:=False;
bPrev.Enabled:=False;
end else
begin
bFirst.Enabled:=True;
bPrev.Enabled:=True;
end;
if ListBox2.Selected[NumRecs -1]=True then
begin
bNext.Enabled:=False;
bLast.Enabled:=False;
bFirst.Enabled:=True;
bPrev.Enabled:=True;
end else
begin
bNext.Enabled:=True;
bLast.Enabled:=True;
end;
end;
//--------------------------------- Free Navigator ----------------------------
procedure TForm1.bFirstClick(Sender: TObject);
begin
With ListBox2 do
begin
Selected[0]:=True;
OnClick(NIL);
bFirst.Enabled:=False;
bPrev.Enabled:=False;
bNext.Enabled:=True;
bLast.Enabled:=True;
end;
end;
procedure TForm1.bPrevClick(Sender: TObject);
begin
(Instead of a ListBox, a StringList works much faster...}
With ListBox2 do
begin
if ItemIndex = 0 then
begin
bFirst.OnClick(Self);
Exit;
end;
Selected[ListBox2.ItemIndex - 1 ]:=True;
OnClick(NIL);
bFirst.Enabled:=True;
bPrev.Enabled:=True;
bNext.Enabled:=True;
bLast.Enabled:=True;
end;
end;
procedure TForm1.bNextClick(Sender: TObject);
begin
With ListBox2 do
begin
if ItemIndex = NumRecs -1 then
begin
bLast.OnClick(Self);
Exit;
end;
Selected[ListBox2.ItemIndex + 1 ]:=True;
OnClick(NIL);
bFirst.Enabled:=True;
bPrev.Enabled:=True;
bNext.Enabled:=True;
bLast.Enabled:=True;
end;
end;
procedure TForm1.bLastClick(Sender: TObject);
begin
With ListBox2 do
begin
Selected[NumRecs-1]:=True;
OnClick(NIL);
bFirst.Enabled:=True;
bPrev.Enabled:=True;
bNext.Enabled:=False;
bLast.Enabled:=False;
end;
end;
procedure TForm1.cmdLoadClick(Sender: TObject);
begin
if not OpenDialog1.Execute then Exit;
FileName:=OpenDialog1.FileName;
try
ListBox2.Items.LoadFromFile(ChangeFileExt(FileName,'.MDX'));
Except
MessageDlg('Error while loading Index file!',mtError,[mbAbort],0);
Exit;
end;
NumRecs:=ListBox2.Items.Count;
ListBox2.Selected[0]:=True;
UpdateButtons;
ListBox2.OnClick(Self);
end;
end.