利用Delphi的“File Of Type”创建并管理属于你自己的“数据库”

来源:互联网 时间:1970-01-01

原作者:Zarko Gajic
原文在:http://delphi.about.com/od/fileio/a/fileof_delphi.htm
译  者:LihuaSoft
二次转载:http://86698409.blog.163.com/blog/static/3786833420074225272711/

前言

在程序中,我们需要用一个途径去把一些有规律的信息存储在磁盘上。不能用TXT格式的文件──因为它不是基于“记录”的,而且管理很不方便。
BDE或ADO也就是说Paradox、Access……唉,不列举了──这些我都不想用,尤其不想用BDE。我要用的是ASCII文本文件。Delphi能做到吗?当然能!这就是“File Of”类型文件,或者说files of some type/binary files。
(译者注:与所有的Win32桌面应用程序编译器相比,Delphi有一个很独到的特点:它编译的Exe可以不需要一些公共动态链接库的支持,尽管因此Delphi的EXE文件可能大一点。而VC、C++Builder、VFP等等这些我用过的编译器,却不是这样,它们编译的EXE往往需要打包一些Dll才可以用。那么,我们用Delphi开发数据库程序时,使用BDE、ADO等等引擎,却因此给Delphi蒙羞──BDE、ADO等等,一般都需要单独安装到操作系统中去。)
下面举例演示这个应用。

首先

我们首先要定义一个基类,也就是一个记录结构:

type
  TMember = record
    Name : string[10];
    eMail : string[20];
    Posts : LongInt;
  end;

然后声明一个记录集,假设有5条记录:
 var Members : array[1..5] of TMember; 
在我们读写我们的数据信息前,我们需要声明一个基于我们记录结构的文件变量:
var F : file of TMember; 
注:在Delphi里,我们声明一个文件变量的一般格式就是:
var SomeTypedFile : file of SomeType;
这里所说的基类(Some Type),比如可以是Double、数组、记录。但不能是长字符串格式、动态数组、类类型以及指针。
接下来我们要把我们的“数据库”文件链接到我们的程序里去:
AssignFile(F, 'Members.dat') ;
使用一个“文件”,我们需要这样“打开”它,并调用Reset方法打开一个已存在于硬盘上的文件,用Rewrite方法去创建一个新文件。当文件使用完毕,关闭应用程序之前,我们要记得用CloseFile方法“关闭”它。如果忘记关闭,将引起一个I/O错误。当文件句柄被关闭,此前对它的所有更新操作将应用。
(译者注:上面所说的“文件”,不仅仅包括磁盘文件,而且包括串口、打印机、其他设备……这些都是“文件”。)

写入到文件

假设我们已经填充了Members里的5条记录。那么,接下来就是把这5条记录写入磁盘文件的代码:
var
  F : file of TMember;
  i : integer;
begin
 AssignFile(F,'members.dat') ;
 Rewrite(F) ;
 try
  for i:= 1 to 5 do
   Write (F, Members[i]) ;
 finally
  CloseFile(F) ;
 end;
end;

从磁盘文件读出所有记录

var
  Member: Tmember;
  F : file of TMember;
begin
 AssignFile(F,'members.dat') ;
 Reset(F) ;
 try
  while not Eof(F) do begin
   Read (F, Member) ;
   {DoSomethingWithMember;}
  end;
 finally
  CloseFile(F) ;
 end;
end; 
注:EOF是文件的结束标志。我们通过判断它的真假,来知道哪里是文件里最后的一条记录。

Seeking and Positioning

文件记录通常是要不断更新的。在一般情况下,我们读写一条记录后,游标立即指向下一条记录。我们可以用下面的方法实现在记录间自由移动游标:

{ 回到文件头,即第1条记录 }
Seek(F, 0) ;

{ 跳到第3条记录 }
Seek(F, 3) ;

{ 跳到文件尾,即最后一条记录的后面 }
Seek(F, FileSize(F)) ;

记录的更新

前面我们仅仅学习了如何读写记录。那么如果我们要求找到第10条记录,然后把这条记录的某个字段(如:Email)修改一下,怎么做?请看下面的代码:

procedure ChangeEMail(const RecN : integer; const NewEMail : string) ;
var DummyMember : TMember;
begin
 { assign, open, exception handling 模块略 }
 Seek(F, RecN) ;
 Read(F, DummyMember) ;
 DummyMember.Email := NewEMail;
 { 此时游标已下移,我们需要重新返回游标位置 }
 Seek(F, RecN) ;
 Write(F, DummyMember) ;
 { 关闭文件 }
end;

结束语
至此,我们已经知道如何写记录到磁盘文件,如何读取,如何仅仅改变文件中间某条记录的一部分数据。

附:一个完整的例子代码

(译者注:这个完整的例子代码是由译者附加的,在Delphi6 + Windows2000上编译通过。因时间紧,没有写“添加”“删除”一条记录的代码。基于本文及本例,读者完全可以写一个控件,完成象BDE、ADO那样的功能。)

unit Unt_Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TFrm_Main = class(TForm)
    Btn_FillDemoData: TButton;
    Btn_ReadAll: TButton;
    Edt_Name: TEdit;
    Edt_Email: TEdit;
    Edt_Posts: TEdit;
    Btn_GoFirst: TButton;
    Btn_Go4th: TButton;
    Btn_GoLastRecord: TButton;
    Btn_ReWriteNowRec: TButton;
    Btn_Next: TButton;
    Btn_Previous: TButton;
    procedure Btn_FillDemoDataClick(Sender: TObject);
    procedure Btn_ReadAllClick(Sender: TObject);
    procedure Btn_GoFirstClick(Sender: TObject);
    procedure Btn_Go4thClick(Sender: TObject);
    procedure Btn_GoLastRecordClick(Sender: TObject);
    procedure Btn_NextClick(Sender: TObject);
    procedure Btn_PreviousClick(Sender: TObject);
    procedure Btn_ReWriteNowRecClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Frm_Main: TFrm_Main;

implementation

{$R *.dfm}

type
  TMember = record
    Name : string[10];
    eMail : string[20];
    Posts : LongInt;
  end;

const
  DBFname : string = 'c:/members.dat';
var
  Members : array[1..5] of TMember;
  aMember : TMember;
  nowRecNo: integer = -1;

procedure MembersInit;
begin
  Members[1].Name := 'TheFirst';
  Members[1].eMail:= '[email protected]';
  Members[1].Posts:= 262201;
  Members[2].Name := 'TheSecond';
  Members[2].eMail:= '[email protected]';
  Members[2].Posts:= 262202;
  Members[3].Name := 'TheThird';
  Members[3].eMail:= '[email protected]';
  Members[3].Posts:= 262203;
  Members[4].Name := 'The4th';
  Members[4].eMail:= '[email protected]';
  Members[4].Posts:= 262204;
  Members[5].Name := 'The5th';
  Members[5].eMail:= '[email protected]';
  Members[5].Posts:= 262205;
end;

function SeekRec(RecNo : integer; var aMember : TMember):boolean;
var
  F : file of TMember;
begin
  AssignFile(F,DBFname) ;
  Reset(F) ;
  try
    Seek(F,RecNo-1);
    Read (F, aMember);
    Result := True;
  Except
    Result := False;
  end;
  CloseFile(F);
end;

function UpdateRec(RecNo : integer; var aMember : TMember):boolean;
var
  F : file of TMember;
begin
  AssignFile(F,DBFname) ;
  Reset(F) ;
  try
    Seek(F,RecNo-1);
    Write(F, aMember);
    Result := True;
  Except
    Result := False;
  end;
  CloseFile(F);
end;

procedure TFrm_Main.Btn_FillDemoDataClick(Sender: TObject);
var
  F : file of TMember;
  i : integer;
begin
  MembersInit;
  AssignFile(F,DBFname) ;
  Rewrite(F) ;
  try
    for i:= Low(Members) to High(Members) do
        Write (F, Members[i]) ;
  finally
    CloseFile(F) ;
  end;
end;

procedure TFrm_Main.Btn_ReadAllClick(Sender: TObject);
var
  Member: TMember;
  F : file of TMember;
begin
  AssignFile(F,DBFname) ;
  Reset(F) ;
  try
    while not Eof(F) do begin
       Read (F, Member) ;
      {DoSomethingWithMember;}
    end;
  finally
    CloseFile(F) ;
  end;
end;

procedure TFrm_Main.Btn_GoFirstClick(Sender: TObject);
begin
  nowRecNo := 1;
  if SeekRec(nowRecNo,aMember) then
     begin
     Edt_Name.Text := aMember.Name;
     Edt_Email.Text:= aMember.eMail;
     Edt_Posts.Text:= IntToStr(aMember.Posts);
     end
     else showmessage('Error');
end;

procedure TFrm_Main.Btn_Go4thClick(Sender: TObject);
begin
  nowRecNo := 4;
  if SeekRec(nowRecNo,aMember) then
     begin
     Edt_Name.Text := aMember.Name;
     Edt_Email.Text:= aMember.eMail;
     Edt_Posts.Text:= IntToStr(aMember.Posts);
     end
     else showmessage('Error');
end;

procedure TFrm_Main.Btn_GoLastRecordClick(Sender: TObject);
{ Or Use SeekRec(5,aMember) }
var
  F : file of TMember;
begin
  AssignFile(F,DBFname) ;
  Reset(F) ;
  nowRecNo := FileSize(F);
  try
    Seek(F,nowRecNo-1);
    Read (F, aMember);
    Edt_Name.Text := aMember.Name;
    Edt_Email.Text:= aMember.eMail;
    Edt_Posts.Text:= IntToStr(aMember.Posts);
  Except
    showmessage('Error');
  end;
  CloseFile(F);
end;

procedure TFrm_Main.Btn_NextClick(Sender: TObject);
begin
  nowRecNo := nowRecNo + 1;
  if SeekRec(nowRecNo,aMember) then
     begin
     Edt_Name.Text := aMember.Name;
     Edt_Email.Text:= aMember.eMail;
     Edt_Posts.Text:= IntToStr(aMember.Posts);
     end
     else showmessage('Error');
end;

procedure TFrm_Main.Btn_PreviousClick(Sender: TObject);
begin
  nowRecNo := nowRecNo - 1;
  if SeekRec(nowRecNo,aMember) then
     begin
     Edt_Name.Text := aMember.Name;
     Edt_Email.Text:= aMember.eMail;
     Edt_Posts.Text:= IntToStr(aMember.Posts);
     end
     else showmessage('Error');
end;

procedure TFrm_Main.Btn_ReWriteNowRecClick(Sender: TObject);
begin
  aMember.Name := Edt_Name.Text;
  aMember.eMail:= Edt_Email.Text;
  aMember.Posts:= StrToInt(Trim(Edt_Posts.Text));
  if not UpdateRec(nowRecNo,aMember) then
     showmessage('Error');
end;

end.



相关阅读:
Top