| 前言 在程序中,我們需要用一個途徑去把一些有規律的信息存儲在磁盤上。不能用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:= '1bcdefgh@163.com'; ?? Members[1].Posts:= 262201; ?? Members[2].Name := 'TheSecond'; ?? Members[2].eMail:= '2bcdefgh@163.com'; ?? Members[2].Posts:= 262202; ?? Members[3].Name := 'TheThird'; ?? Members[3].eMail:= '3bcdefgh@163.com'; ?? Members[3].Posts:= 262203; ?? Members[4].Name := 'The4th'; ?? Members[4].eMail:= '4bcdefgh@163.com'; ?? Members[4].Posts:= 262204; ?? Members[5].Name := 'The5th'; ?? Members[5].eMail:= '5bcdefgh@163.com'; ?? 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. |