在軟體開發中,檔案處理是不可或缺的基礎技能。無論是建立設定檔、日誌記錄、資料匯出或是讀取外部資料,文字檔案操作都是程式設計師必須熟練掌握的技術。在 Pascal 語言中,文字檔案的處理機制相當完善與直覺,適合作為理解檔案操作概念的入門基礎。
在這篇文章中,玄貓將帶你深入瞭解 Pascal 中文字檔案的處理機制,從基本概念到實際應用,讓你能夠靈活運用這些知識在實際開發中。
Pascal 文字檔案的基本概念
在 Pascal 中,操作文字檔案需要經過幾個關鍵步驟:宣告檔案變數、關聯檔案名稱、開啟檔案進行讀寫操作,最後關閉檔案。這個流程雖然簡單,但每個步驟都有其重要性。
檔案變數與關聯
首先,我們需要宣告一個 TextFile
型態的變數,然後使用 AssignFile
將此變數與實際檔案名稱關聯:
var
f: TextFile;
begin
AssignFile(f, 'example.txt');
// 後續操作
end;
這段程式碼宣告了一個名為 f
的 TextFile
型態變數,並透過 AssignFile
將它與 ’example.txt’ 檔案關聯。值得注意的是,此操作僅建立變數與檔案名稱的關聯,並不會實際開啟或建立檔案。這類別似於建立一個「指向」特設定檔案的參考,真正的檔案操作發生在後續的開啟步驟。
檔案操作模式
在 Pascal 中,文字檔案有三種主要的開啟模式:
- 寫入模式 (
Rewrite
):建立新檔案或覆寫現有檔案 - 讀取模式 (
Reset
):開啟現有檔案以讀取內容 - 附加模式 (
Append
):開啟現有檔案以在尾端增加內容
一個重要的限制是文字檔案在 Pascal 中無法同時進行讀寫操作,必須選擇其中一種模式。
寫入文字檔案
當我們需要將資料寫入檔案時,首先需要使用 Rewrite
開啟檔案:
AssignFile(f, 'example.txt');
Rewrite(f);
// 現在可以寫入資料
Rewrite
操作會建立一個全新的空檔案。如果同名檔案已存在,則會被覆寫,原有內容將會遺失。這點在處理重要資料時要特別留意。
使用 Write 與 Writeln 函式
寫入檔案的主要函式有 Write
和 Writeln
,它們的行為類別似於控制檯輸出,但第一個引數需要指設定檔案變數:
Procedure ZapFile;
var
f: TextFile;
x, y: integer;
Ok: boolean;
begin
AssignFile(f, 'example.txt');
ReWrite(f);
x := 10;
y := 7;
Writeln(f, x); // 寫入 10 到第一行,遊標移至第二行
Write(f, x+2); // 寫入 12 到第二行,遊標保持在第二行末尾
Write(f, 'Hello'); // 在第二行末尾寫入 "Hello"
Write(f, x, y); // 在遊標位置寫入 10 然後 7 (不含空格)
Writeln(f, x, y); // 寫入 10 然後 7,遊標移至第三行
Ok := 5 > 7;
Writeln(f, Ok); // 寫入 False (Ok 的值)到第三行
Writeln(f, x, ' ', y); // 寫入 "10 7" 到第四行
Writeln(f, 'x=', x); // 寫入 "x=10" 到第五行
CloseFile(f);
end;
這個範例展示了 Write
和 Writeln
的不同行為:
Write
寫入資料後遊標停留在同一行末尾Writeln
寫入資料後會自動換行,遊標移至下一行開頭- 可以連續寫入不同型態的資料,包括整數、字串、布林值等
- 多個引數之間不會自動加入空格,需要明確指定
最後的 CloseFile
非常重要!沒有正確關閉檔案可能導致資料遺失或檔案損壞,因為有些資料可能仍在緩衝區中未實際寫入磁碟。這是初學者容易忽略的關鍵步驟。
使用 Append 模式附加資料
有時我們不想覆寫檔案,而是要在現有檔案末尾增加內容,這時可以使用 Append
模式:
AssignFile(f, 'example.txt');
Append(f);
// 寫入的內容將增加到檔案末尾
使用 Append
時,遊標會自動定位在檔案末尾,所有寫入操作都會從該位置開始。需要注意的是,Append
只能用於已存在的檔案,若檔案不存在將導致執行錯誤。
封裝檔案寫入功能
在實際開發中,我常將檔案操作功能封裝成獨立程式,提高程式碼的可重用性。以下是一個實用範例,可以建立包含特定行列數字的檔案:
procedure ZapZero(var fl: TextFile; n, m: integer);
var
i, j: integer;
begin
Rewrite(fl);
for i := 1 to n do
begin
for j := 1 to m do
write(fl, 0:3);
writeln(fl)
end;
CloseFile(fl)
end;
procedure TForm1.Button1Click(Sender: TObject);
var
f, g: TextFile;
begin
AssignFile(f, 'test1.txt');
AssignFile(g, 'test2.txt');
ZapZero(f, 3, 5); // 3行5列零
ZapZero(g, 4, 3); // 4行3列零
end;
這個範例展示瞭如何封裝檔案操作為可重用的程式:
ZapZero
接收檔案變數和兩個整數引數,分別表示行數和列數- 函式中使用巢狀迴圈產生指定格式的輸出,每個數字佔用3個字元寬度
- 檔案變數以
var
關鍵字傳遞,這在 Pascal 中是必要的,因為檔案變數需要被修改 - 函式內部負責開啟和關閉檔案,簡化了主程式的結構
這種封裝方式在處理多個相似檔案時特別有用,可以大幅減少重複程式碼。
讀取文字檔案
讀取檔案與寫入操作相似,但使用 Reset
函式開啟檔案:
AssignFile(f, 'example.txt');
Reset(f);
// 現在可以讀取資料
使用 Reset
時,檔案必須已存在,否則會產生執行時錯誤。開啟後,遊標會定位在檔案的第一行開頭。
基本讀取操作
最簡單的讀取操作是使用 ReadLn
讀取整行內容:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
begin
AssignFile(f, 'my.txt');
Reset(f);
ReadLn(f, s); // 讀取第一行
memEx1.Lines.Append(s); // 顯示在備忘錄元件中
CloseFile(f);
end;
這段程式碼演示了基本的檔案讀取流程:
- 關聯檔案變數與檔名
- 以讀取模式開啟檔案
- 讀取一行內容到字串變數
- 將讀取的內容顯示在介面元件中
- 關閉檔案
每次執行 ReadLn
後,遊標會自動移至下一行的開頭。這是 Pascal 檔案操作的一個便利特性,簡化了逐行讀取的程式。
讀取多行內容
若要讀取多行內容,可以結合迴圈使用:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
i: integer;
begin
AssignFile(f, 'my.txt');
Reset(f);
For i := 1 to 5 do
begin
ReadLn(f, s);
memEx1.Lines.Append(s);
end;
CloseFile(f);
end;
這段程式碼會讀取檔案中的前五行內容。在實際應用中,我們需要注意檔案可能沒有足夠的行數,這種情況下程式會產生錯誤。因此,在生產環境中應該加入檢查機制,確保不會嘗試讀取超出檔案範圍的內容。
跳過特定行內容
如果我們只想讀取特定行,可以使用不帶變數的 ReadLn(f)
來跳過不需要的行:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
i: integer;
begin
AssignFile(f, 'my.txt');
Reset(f);
For i := 1 to 4 do
ReadLn(f); // 跳過前4行
Readln(f, s); // 讀取第5行
memEx1.Lines.Append(s);
CloseFile(f);
end;
這段程式碼展示瞭如何跳過檔案中的特定行數。不帶變數的 ReadLn(f)
只會移動遊標到下一行,不讀取任何內容。這在只需要處理檔案特定部分時非常有用,可以提高效率。
需要注意的是,Pascal 中的文字檔案是循序存取的,無法直接跳到特定行,必須從頭開始逐行讀取。這是文字檔案處理的一個基本限制。
讀取未知行數的檔案
在實際應用中,我們通常不知道檔案有多少行。為了讀取整個檔案,可以使用 EOF
函式(End Of File):
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
begin
AssignFile(f, 'my.txt');
Reset(f);
While not EOF(f) do
begin
ReadLn(f, s);
memEx1.Lines.Append(s);
end;
CloseFile(f);
end;
這段程式碼使用 EOF(f)
函式檢查是否已到達檔案末尾。只要還沒到末尾,迴圈就會繼續執行,從而讀取檔案中的所有行。這是處理未知長度檔案的標準方法,也是我在實際開發中最常使用的方式。
重要的是,這裡必須使用 ReadLn
而非 Read
。如果使用 Read
,遊標不會自動移至下一行,可能導致無限迴圈,因為永遠不會達到檔案末尾。
檢測行末:EOLN 函式
除了檢測檔案末尾,有時我們需要知道是否到達了行末。Pascal 提供了 EOLN
函式(End Of Line)來檢測遊標是否位於行末:
if EOLN(f) then
// 遊標位於行末
這在需要逐字元處理檔案內容時特別有用,可以幫助確定何時換行。
文字檔案處理的最佳實踐
在多年的開發經驗中,我總結了一些處理文字檔案的最
數值型文字檔案操作:Delphi高效讀取技巧
在前面的文章中,我們瞭解瞭如何逐行讀取文字檔案。今天將進一步探討如何從檔案中讀取以空格分隔的數值資料。這是處理資料檔案時非常實用的技巧,讓我們深入瞭解Delphi如何直接讀取數值型變數。
空格分隔數值的讀取機制
假設我們有一個文字檔案,其中包含由一個或多個空格分隔的數字。當我們使用Read(f, x)
陳述式時(其中f是檔案變數,x是整數變數),系統會如何處理呢?
讓我以實際運作機制說明:
- 執行
Read(f, x)
後,x變數會設為檔案中的第一個數值 - 遊標會停在該數值後的分隔符(空格)上
- 再次執行
Read(f, x)
時,系統會跳過所有分隔符(空格),讀取下一個數值 - 遊標再次停在數值後的分隔符上
簡而言之,Read(f, x)
對整數變數x的操作順序是:跳過數值前的所有分隔符 → 讀取數值到變數 → 將遊標停在數值後的非數字符號處。
實戰範例:讀取空格分隔的數值
讓我們透過一個例項來理解這個機制:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
x, i, k: integer;
begin
AssignFile(f, 'my.txt'); // 關聯檔案名稱和檔案變數
Reset(f); // 開啟檔案以供讀取
k := 0;
For i := 1 to 5 do // 執行五次:
begin
Read(f, x); // 讀取下一個數字
k := k + x; // 將讀取的數字加到總和中
end;
CloseFile(f); // 關閉檔案
end;
這段程式碼開啟名為’my.txt’的檔案,然後連續讀取五個數字並計算它們的總和。假設檔案內容為「10 7 25 14 1…」,那麼執行後k變數將包含57(即10+7+25+14+1)。注意Read(f, x)
會自動跳過所有空格,直接讀取數值。這是處理以空格分隔的數值檔案的高效方法。
Read與ReadLn的關鍵差異
如果我們將上面範例中的Read(f, x)
改為ReadLn(f, x)
會發生什麼?這兩個函式有著關鍵性的差異:
Read
讀取下一個數值,遊標停在數值後的分隔符上ReadLn
讀取當前行的下一個數值,然後將遊標移到下一行的開頭
讓我們修改範例看區別:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
x, i, k: integer;
begin
AssignFile(f, 'my.txt'); // 關聯檔案名稱和檔案變數
Reset(f); // 開啟檔案以供讀取
k := 0;
For i := 1 to 5 do // 執行五次:
begin
ReadLn(f, x); // 讀取行首的數字並移至下一行
k := k + x; // 將讀取的數字加到總和中
end;
CloseFile(f); // 關閉檔案
end;
這個版本使用ReadLn
而非Read
,它只會讀取每行的第一個數字,然後跳到下一行。假設檔案的前五行分別以10、14、24、27和11開頭,執行此程式後k變數將包含86(10+14+24+27+11)。這種讀取方式適合當每行只需讀取第一個數值的情境。
讀取一行中所有數值的挑戰
在實際應用中,我們經常需要讀取一行中的所有數字,但事先不知道數量。直覺上,我們可能會使用EOLN(f)
函式來檢查行尾:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
x, k: integer;
begin
AssignFile(f, 'my.txt'); // 關聯檔案名稱和檔案變數
Reset(f); // 開啟檔案以供讀取
k := 0;
While not EOLN(f) do // 當未到行尾時迴圈
begin
Read(f, x); // 讀取下一個數字
k := k + x; // 將讀取的數字加到總和中
end;
CloseFile(f); // 關閉檔案
end;
這段程式碼看似能讀取第一行的所有數字(例如"10 7 25",總和為42),但實際上可能會出問題。如果最後一個數字後有空格,EOLN(f)
會回傳False,因為空格不是行尾符號。這會導致程式繼續執行Read(f, x)
,跳過所有分隔符(包括行尾符號),直到讀到下一行的數字。結果會讀取多行資料,而非僅限於第一行。
SeekEOLN與SeekEOF:解決空格問題的關鍵函式
為瞭解決上述問題,Delphi提供了兩個特殊函式:
SeekEOLN(f)
:先跳過所有空格,然後檢查是否到達行尾SeekEOF(f)
:跳過所有空格和行尾符號,然後檢查是否到達檔案尾
正確讀取一行中所有數值
使用SeekEOLN
可以解決我們前面遇到的問題:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
x, k: integer;
begin
AssignFile(f, 'my.txt'); // 關聯檔案名稱和檔案變數
Reset(f); // 開啟檔案以供讀取
k := 0;
While not SeekEOLN(f) do // 當未到行尾時迴圈(先跳過空格)
begin
Read(f, x); // 讀取下一個數字
k := k + x; // 將讀取的數字加到總和中
end;
CloseFile(f); // 關閉檔案
end;
這個版本使用SeekEOLN(f)
代替EOLN(f)
,它會先跳過所有空格再檢查行尾,因此能正確處理數字後有空格的情況。不論行尾是否有空格,這段程式碼都能正確讀取第一行的所有數字。在我的實際開發中,這個細節常被忽略,但卻是處理數值檔案時的關鍵。
讀取整個檔案的所有數值
如果要讀取檔案中的所有數值,可以使用SeekEOF
函式:
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f: TextFile;
s: string;
x, k: integer;
begin
AssignFile(f, 'my.txt'); // 關聯檔案名稱和檔案變數
Reset(f); // 開啟檔案以供讀取
k := 0;
While not SeekEOF(f) do // 當未到檔案尾時迴圈(跳過空格和行尾)
begin
Read(f, x); // 讀取下一個數字
k := k + x; // 將讀取的數字加到總和中
end;
CloseFile(f); // 關閉檔案
end;
這段程式碼使用SeekEOF(f)
,能夠讀取整個檔案中的所有數字並計算總和,不受行尾空格或換行符的影響。當處理多行數值資料時,這是最可靠的方法。從經驗來看,這種寫法在處理大型數值檔案時特別有用,它能確保不會漏讀任何數值。
檔案讀取的黃金法則
根據我多年的開發經驗,處理文字檔案讀取時,可以遵循以下規則:
- 如果您以行為單位讀取資料,使用
EOLN(f)
和EOF(f)
函式 - 如果您以數值為單位讀取資料,使用
SeekEOLN(f)
和SeekEOF(f)
函式
這個簡單的法則能幫助你避免許多檔案讀取中的常見陷阱。
錯誤處理注意事項
當程式嘗試從非數值資料(檔案尾或純文字)讀取數值時,執行時系統會顯示錯誤訊息並終止程式執行。以下情況也會導致程式中斷:
- 嘗試將實數讀入整數變數
- 檔案中的數字格式不符合Delphi格式(如使用逗號而非句點作為小數點分隔符)
在實際應用中,建議加入適當的錯誤處理機制,例如使用try-except結構來捕捉可能的讀取異常。
實用練習題:鞏固你的檔案處理技能
以下是一些實用練習題,可幫助你鞏固文字檔案處理技能:
練習1:尋找最短行
編寫一個程式,找出檔案中最短的一行並將其內容顯示在Label元件中。如有多個等長的最短行,顯示最後一個。檔案名稱應從文字框讀取。
練習2:迴文行檢測
編寫一個程式,讀取檔案中的每一行,並將迴文行輸出到TMemo元件中。檔案名稱應從文字框輸入(可使用對話方塊)。
練習3:偶數和行篩選
一個文字檔案包含多行,每行包含幾個由一個或多個空格分隔的整數。編寫一個程式,讀取該檔案並將只包含偶數和的行寫入另一個檔案。檔案名稱從文字框輸入。
練習4:奧林匹克參與者分析
一個文字檔案包含參加奧林匹克的兒童和學校的資訊。第一行包含兒童記錄的數量,隨後的每一行格式如下:
<姓氏> <縮寫> <學校編號>
其中<姓氏>
是不超過20個符號的字串,<縮寫>
是包含四個符號的字串(字元、句點、字元、句點),<學校編號>
是一位或兩位數字。各項之間用單個空格分隔。
編寫一個程式,輸出參與者人數最少的學校編號。如果有多個學校擁有相同最少數量的參與者,應以逗號分隔列出所有學校編號。
這些練習題涵蓋了不同的檔案處理場景,從基本的行處理到複雜的資料分析,能幫助你全面掌握Delphi的檔案處理技術。
文字檔案處理的進階思考
在處理文字檔案時,我發現許多開發者容易忽略效能考量。當處理大型檔案時,讀取策略會直接影響程式的執行效率。在我的實踐中,對於需要重複處理的大型檔案,通常會考慮以下最佳化策略:
- 使用緩衝技術,一次讀取多行進行批次處理
- 對於格式已知的數值檔案,使用更高效的二進位讀取
- 實作讀取進度指示器,特別是處理時間可能較長的大檔案
這些進階技巧能顯著提升檔案處理效率,特別是在處理資料密集型應用時。
文字檔案操作是幾乎所有應用程式開發中都會遇到的基礎課題。掌握了本文介紹的技術,特別是理解了Read/ReadLn和
Delphi 標準檔案對話方塊:提升使用者經驗的檔案操作方式
在開發桌面應用程式時,提供友善的檔案選擇介面是提升使用者經驗的關鍵。雖然在前面我們已經學習了基本的檔案操作方法,但這些方法通常需要預先知道檔案路徑,對一般使用者來說並不直覺。今天玄貓要帶大家探討 Delphi 中的標準檔案對話方塊元件,這些元件能讓使用者透過熟悉的視窗介面選擇檔案,大幅提升應用程式的易用性。
標準檔案對話方塊元件概述
Delphi 提供了兩個主要的檔案對話方塊元件,位於工具箱的 Dialogs 標籤中:
- OpenDialog:用於選擇已存在的檔案進行讀取操作
- SaveDialog:用於選擇存檔位置,可以是已存在的檔案或新建檔案
這些元件放置於表單後,在程式執行時並不會直接顯示,而是需要透過程式碼觸發。與傳統檔案操作相比,這種方式更加直覺與符合現代桌面應用程式的操作習慣。
檔案對話方塊的核心屬性與方法
檔案對話方塊元件有兩個關鍵的元素:
- FileName 屬性:存放使用者選擇的檔案完整路徑
- Execute 方法:顯示對話方塊並回傳一個布林值,表示使用者是否完成了檔案選擇
當使用者在對話方塊中選擇檔案並點選「開啟」或「儲存」按鈕時,Execute 方法會回傳 True,同時 FileName 屬性將包含選設定檔案的完整路徑。如果使用者取消操作,Execute 將回傳 False。
使用檔案對話方塊的基本流程
使用檔案對話方塊進行檔案操作的基本流程如下:
var
Okf1, Okf2: Boolean;
StF1, StF2: string;
begin
// 檢查是否選擇了讀取檔案
Okf1 := OpenDialog1.Execute;
if Okf1 then
begin
StF1 := OpenDialog1.FileName;
AssignFile(f, StF1);
Reset(f);
// 處理檔案資訊:讀取、處理等
CloseFile(f);
end;
// 檢查是否選擇了寫入檔案
Okf2 := SaveDialog1.Execute;
if Okf2 then
begin
StF2 := SaveDialog1.FileName;
AssignFile(g, StF2);
Rewrite(g);
// 寫入資訊到檔案
CloseFile(g);
end;
end;
這個流程將傳統的檔案操作與標準對話方塊結合,讓使用者能夠直覺地選擇檔案,同時保持了 Delphi 檔案處理的基本結構。
實作 OpenDialog 讀取檔案
讓我們深入瞭解如何使用 OpenDialog 元件來讀取檔案。首先,我們需要在表單上放置一個 OpenDialog 元件,然後實作相關程式碼:
var
f: TextFile;
Okf1: Boolean;
StF1: string;
line: string;
begin
// 顯示開啟檔案對話方塊
Okf1 := OpenDialog1.Execute;
// 如果使用者選擇了檔案
if Okf1 then
begin
// 取得檔案名稱
StF1 := OpenDialog1.FileName;
// 指派檔案變數
AssignFile(f, StF1);
// 開啟檔案進行讀取
Reset(f);
// 讀取檔案內容
while not Eof(f) do
begin
ReadLn(f, line);
Memo1.Lines.Add(line);
end;
// 關閉檔案
CloseFile(f);
end;
end;
這段程式碼示範了使用 OpenDialog 讀取文字檔案的完整流程。當執行 OpenDialog1.Execute
時,系統會顯示標準的檔案開啟對話方塊,使用者可以瀏覽檔案系統並選擇要開啟的檔案。
如果使用者選擇了檔案(按下「開啟」按鈕),Execute
方法回傳 True,我們就從 OpenDialog1.FileName
屬性中取得完整的檔案路徑,並使用標準的檔案操作程式開啟檔案。在這個例子中,我們讀取檔案的每一行,並將內容增加到一個 Memo 元件中顯示。
值得注意的是,這種方式讓使用者可以自由選擇任何位置的檔案,而不需要預先知道檔案路徑,大提高了應用程式的靈活性。
實作 SaveDialog 儲存檔案
同樣地,我們可以使用 SaveDialog 元件來實作檔案的儲存功能:
var
g: TextFile;
Okf2: Boolean;
StF2: string;
begin
// 顯示儲存檔案對話方塊
Okf2 := SaveDialog1.Execute;
// 如果使用者選擇了儲存位置
if Okf2 then
begin
// 取得檔案名稱
StF2 := SaveDialog1.FileName;
// 指派檔案變數
AssignFile(g, StF2);
// 開啟檔案進行寫入
Rewrite(g);
// 寫入 Memo 內容到檔案
WriteLn(g, Memo1.Text);
// 關閉檔案
CloseFile(g);
ShowMessage('檔案已成功儲存!');
end;
end;
這段程式碼展示了 SaveDialog 的基本使用方式。當執行 SaveDialog1.Execute
時,系統會顯示標準的檔案儲存對話方塊。使用者可以選擇一個已存在的檔案進行覆寫,或者輸入一個新的檔案名稱。
如果使用者完成選擇(按下「儲存」按鈕),我們就從 SaveDialog1.FileName
屬性取得檔案路徑,然後使用 Rewrite
開啟檔案進行寫入。在這個例子中,我們將一個 Memo 元件的內容寫入到檔案中。
這種方式讓使用者可以自由選擇儲存位置,同時也提供了一個標準的介面來確認檔案覆寫操作,增強了應用程式的安全性。
增強檔案對話方塊的功能
標準的檔案對話方塊還有許多屬性可以用來增強其功能:
設定檔案過濾器
我們可以透過 Filter 屬性設定檔案對話方塊中顯示的檔案類別:
procedure TForm1.FormCreate(Sender: TObject);
begin
OpenDialog1.Filter := 'Text files (*.txt)|*.txt|All files (*.*)|*.*';
SaveDialog1.Filter := 'Text files (*.txt)|*.txt|All files (*.*)|*.*';
// 設定預設選擇的過濾器索引
OpenDialog1.FilterIndex := 1;
SaveDialog1.FilterIndex := 1;
end;
這段程式碼設定了檔案對話方塊的過濾器,使其預設只顯示文字檔案(*.txt)。Filter 屬性的格式為 描述|過濾器|描述|過濾器...
,可以設定多個過濾選項。FilterIndex 屬性則指定預設選擇哪一個過濾器,索引值從 1 開始。
這樣設定後,當使用者開啟檔案對話方塊時,會看到一個下拉選單,可以選擇「Text files (.txt)」或「All files (.)」,預設選擇的是「Text files (.txt)」。
設定初始目錄
我們可以透過 InitialDir 屬性設定檔案對話方塊的初始目錄:
OpenDialog1.InitialDir := ExtractFilePath(Application.ExeName);
SaveDialog1.InitialDir := GetMyDocumentsPath; // 自定義函式,取得「我的檔案」路徑
這裡我們設定 OpenDialog 的初始目錄為應用程式所在的資料夾,而 SaveDialog 的初始目錄為使用者的「我的檔案」資料夾。這樣可以讓檔案對話方塊在開啟時直接導航到最可能的位置,提高使用者效率。
ExtractFilePath(Application.ExeName)
是 Delphi 提供的函式,用於取得應用程式執行檔所在的路徑。而 GetMyDocumentsPath
則是一個自定義函式,用於取得「我的檔案」的路徑。
設定預設檔案名稱
對於 SaveDialog,我們可以設定一個預設的檔案名稱:
SaveDialog1.FileName := 'output.txt';
這行程式碼設定了 SaveDialog 的預設檔案名稱為 “output.txt”。當使用者開啟儲存對話方塊時,這個名稱會預先填入檔案名稱欄位中,使用者可以直接受或修改它。這對於提供一個有意義的預設名稱很有用,尤其是當檔案名稱應該反映其內容或生成日期時。
實用範例:檔案內容處理
現在讓我們來看一個更完整的範例,結合 OpenDialog 和 SaveDialog 來處理檔案內容:
procedure TForm1.btnProcessClick(Sender: TObject);
var
inputFile, evenFile, oddFile: TextFile;
line: string;
okInput, okEven, okOdd: Boolean;
begin
// 選擇輸入檔案
okInput := OpenDialog1.Execute;
if not okInput then Exit;
// 選擇存放偶數長度字串的檔案
SaveDialog1.Title := '儲存偶數長度字串';
SaveDialog1.FileName := 'even.txt';
okEven := SaveDialog1.Execute;
if not okEven then Exit;
// 選擇存放奇數長度字串的檔案
SaveDialog1.Title := '儲存奇數長度字串';
SaveDialog1.FileName := 'odd.txt';
okOdd := SaveDialog1.Execute;
if not okOdd then Exit;
// 開啟所有檔案
AssignFile(inputFile, OpenDialog1.FileName);
AssignFile(evenFile, SaveDialog1.FileName);
Reset(inputFile);
Rewrite(evenFile);
// 重新執行 SaveDialog 取得第二個檔案名稱
AssignFile(oddFile, SaveDialog1.FileName);
Rewrite(oddFile);
// 處理檔案內容
while not Eof(inputFile) do
begin
ReadLn(inputFile, line);
// 判斷字串長度的奇偶性
if Length(line) mod 2 = 0 then
WriteLn(evenFile, line) // 偶數長度
else
WriteLn(oddFile, line); // 奇數長度
end;
// 關閉所有檔案
CloseFile(inputFile);
CloseFile(evenFile);
CloseFile(oddFile);
ShowMessage('處理完成!');
end;
這個範例展示瞭如何使用檔案對話方塊來處理檔案內容。程式首先讓使用者選擇一個輸入檔案,然後分別選擇兩個輸出檔案用於儲存不同的處理結果。
程式讀取輸入檔案的每一行,判斷其長度是奇數還是偶數,然後將其寫入相應的輸出檔案中。這個例子展示瞭如何在一個操作中使用多個檔案對話方塊,以及如何根據需要修改對話方塊的屬性(如標題和預設檔案名)。
注意我們如何透過設定 SaveDialog1.Title 屬性來提供更明確的提示,讓使用者瞭解每個對話方塊的用途。這種小細節可以大幅提升應用程式的使用者經驗。