在 Delphi 開發中,檔案處理是不可或缺的一部分。本文將示範如何使用 TStreamWriterTStreamReader 簡化文字檔的讀寫操作。同時,我們也將探討如何使用 JSON 格式儲存結構化資料,並示範使用 TJSONObjectTJsonTextWriter 兩種方式生成 JSON 資料,最後將其寫入檔案。透過這些技巧,可以更有效率地處理檔案,並提升資料儲存的結構性。程式碼範例中詳細展示瞭如何讀取我的最愛清單,並將其轉換為文字和 JSON 格式儲存,方便後續讀取和應用。這兩種方法各有優劣,TJSONObject 適合建立複雜的 JSON 結構,而 TJsonTextWriter 則更注重效能和程式碼可讀性。

使用 TStreamWriter 和 TStreamReader 處理文字檔

在程式開發中,檔案操作是常見的需求。Delphi 提供多種方式來建立和操作檔案,例如使用內建函式、專門的類別(如 TMemoTIniFile),或是 System.IOUtils 單元中的 TFile 類別。不過,最簡便的方法是使用 System.Classes 單元中的 TStreamWriterTStreamReader 類別,它們提供了一個優雅的程式設計模型來進行檔案操作。

建立範例應用程式

首先,我們在主表單上新增一個按鈕,用於顯示另一個表單,在那裡我們將嘗試不同的文字檔處理方法。將新表單儲存在 uFormFavTextFiles 單元中,並將表單重新命名為 FormFavTextFiles

導航程式碼實作

在主表單中,我們新增一個按鈕點選事件,用於顯示 FormFavTextFiles

uses
  uFormFavTextFiles;

procedure TFormFavMain.BtnTextFilesClick(Sender: TObject);
begin
  FormFavTextFiles.Show;
end;

同樣地,在 FormFavTextFiles 中,我們新增一個按鈕點選事件,用於傳回主表單。

使用 TStreamWriter 和 TStreamReader

FormFavTextFiles 上,我們新增兩個按鈕和一個 TMemo 元件,分別用於寫入和讀取我的最愛清單到文字檔,並顯示結果。

取得檔案名稱的函式

首先,我們定義一個 GetFilename 函式,用於集中管理檔案名稱的存取:

uses
  uFormFavMain, uFavorite, System.IOUtils;

function TFormFavTextFiles.GetFilename: string;
begin
  Result := TPath.Combine(TPath.GetDocumentsPath, 'favs.txt');
end;

這個函式使用 TPath.Combine 方法來組合檔案路徑和檔名,以確保跨平台相容性。

寫入我的最愛到文字檔

當第一個按鈕被點選時,我們將我的最愛清單寫入到文字檔:

procedure TFormFavTextFiles.BtnWriteClick(Sender: TObject);
var
  SW: TStreamWriter;
  Fav: TFavorite;
  Favs: TFavorites;
begin
  Favs := FormFavMain.Favs;
  SW := TStreamWriter.Create(GetFilename, False, TEncoding.UTF8);
  try
    for Fav in Favs do
    begin
      SW.WriteLine(Fav.URL);
      SW.WriteLine(Fav.Caption);
    end;
  finally
    SW.Free;
  end;
end;

#### 內容解密:

  • 此段程式碼首先取得主表單中的我的最愛清單,並建立一個 TStreamWriter 物件用於寫入檔案。
  • 使用迴圈遍歷我的最愛清單,將每個專案的 URL 和 Caption 寫入檔案。
  • 使用 TEncoding.UTF8 編碼確保檔案內容的正確性。
  • 最後釋放 TStreamWriter 物件以避免記憶體洩漏。

讀取文字檔內容

當第二個按鈕被點選時,我們讀取文字檔的內容並顯示在 Memo 中:

procedure TFormFavTextFiles.BtnReadClick(Sender: TObject);
var
  SR: TStreamReader;
begin
  SR := TStreamReader.Create(GetFilename, TEncoding.UTF8);
  try
    while not SR.EndOfStream do
      MemoLog.Lines.Add(SR.ReadLine);
  finally
    SR.Free;
  end;
end;

#### 內容解密:

  • 此段程式碼建立一個 TStreamReader 物件用於讀取檔案。
  • 使用迴圈讀取檔案的每一行,並將其新增到 Memo 的 Lines 中。
  • 使用 TEncoding.UTF8 編碼確保檔案內容的正確性。
  • 最後釋放 TStreamReader 物件以避免記憶體洩漏。

JSON 資料處理簡介

雖然使用 TStreamWriterTStreamReader 可以實作基本的檔案操作,但資料缺乏結構化。對於我的最愛清單這種結構化資料,使用 JSON 格式儲存會更合適。Delphi 提供兩種方式來處理 JSON 資料:建立記憶體中的 JSON 物件樹,或是使用串流方式順序存取 JSON 資料。接下來,我們將探討如何使用 JSON 來儲存和讀取我的最愛清單。

圖表翻譯: 此圖表呈現了使用 TStreamWriterTStreamReader 處理文字檔的流程。首先,建立 TStreamWriter 將我的最愛清單寫入檔案;然後,建立 TStreamReader 讀取檔案內容並顯示在 Memo 中。整個過程確保了資料的正確寫入和讀取。

使用JSON進行資料交換

JSON是一種非常流行的資料交換格式,用於分享資訊和各類別資料集。假設你剛剛在本機下載了一份JSON資料,接下來該怎麼做呢?

JSON範例

以下是一個表示收藏資訊的JSON範例:

{
  "Favorites": [
    {
      "URL": "www.embarcadero.com/products/delphi",
      "Caption": "Delphi Home Page"
    },
    {
      "URL": "docwiki.embarcadero.com/RADStudio/en",
      "Caption": "RAD Studio online documentation"
    }
  ]
}

與最初建立的純文字檔不同,JSON中的收藏資料結構更為嚴謹。這裡有一個物件,只有一個名為Favorites的屬性,其值是一個包含兩個物件的陣列。陣列中的每個物件都有兩個字串屬性:URLCaption

對於程式設計師來說,一個典型的目標是將JSON資料轉換成可以在程式碼中操作的程式語言結構,或從程式輸出JSON文字。

建立JSON

首先,我們來看看生成JSON的不同方法。我們將把這些資訊儲存到檔案中,稍後再將這些資訊讀回本地的收藏清單。

取得檔案名稱

我們首先實作一個GetFilename函式,用於寫入和讀取favs.json檔案:

function TFormFavJSON.GetFilename: string;
begin
  Result := TPath.Combine(TPath.GetDocumentsPath, 'favs.json');
end;

將JSON文字寫入檔案

我們還需要一個簡單的函式,將包含JSON文字的字串寫入檔案。使用TStreamWriter類別,可以輕鬆實作這一點:

procedure TFormFavJSON.WriteJsonTextToFile(txt: string);
var
  sw: TStreamWriter;
begin
  sw := TStreamWriter.Create(GetFilename, False, TEncoding.UTF8);
  try
    sw.WriteLine(txt);
  finally
    sw.Free;
  end;
end;

使用DOM生成JSON

第一種生成JSON的方法是建立一個記憶體中的JSON資料圖形,然後一次性將其轉換為字串。為此,我們將定義FavListToJsonTextWithDOM方法,該方法將從demo app主表單的全域TFavorites清單中生成JSON文字:

function TFormFavJSON.FavListToJsonTextWithDOM: string;
var
  Fav: TFavorite;
  Favs: TFavorites;
  ObjFavs, ObjF: TJSONObject;
  ArrFavs: TJSONArray;
begin
  Favs := FormFavMain.Favs;
  ObjFavs := TJSONObject.Create;
  try
    ArrFavs := TJSONArray.Create;
    for Fav in Favs do
    begin
      ObjF := TJSONObject.Create;
      ObjF.AddPair('URL', TJSONString.Create(Fav.URL));
      ObjF.AddPair('Caption', TJSONString.Create(Fav.Caption));
      ArrFavs.Add(ObjF);
    end;
    ObjFavs.AddPair('Favorites', ArrFavs);
    Result := ObjFavs.ToString;
  finally
    ObjFavs.Free;
  end;
end;

程式碼解密:

  1. 初始化變數:首先,我們從主表單取得Favs,並建立一個名為ObjFavsTJSONObject例項。
  2. 建立JSON陣列:我們建立一個名為ArrFavsTJSONArray,用於儲存多個TFavorite物件。
  3. 迴圈處理:遍歷Favs中的每個TFavorite物件,建立對應的TJSONObjectObjF),並新增URLCaption屬性。
  4. 加入陣列:將每個ObjF加入到ArrFavs中。
  5. 組合JSON物件:將ArrFavs加入到ObjFavs中,並以Favorites為屬性名稱。
  6. 輸出JSON字串:呼叫ObjFavs.ToString將整個JSON物件轉換為字串。
  7. 資源釋放:最後,釋放ObjFavs,它會自動釋放其擁有的所有子物件。

在表單上新增一個按鈕,將其Caption屬性設為「Write with JSON DOM」,並在其OnClick事件中輸入以下程式碼:

procedure TFormFavJSON.btnWriteDOMClick(Sender: TObject);
var
  S: string;
begin
  S := FavListToJsonTextWithDOM;
  WriteJsonTextToFile(S);
end;

使用TJsonTextWriter生成JSON

第二種生成JSON的方法涉及使用 TJsonTextWriter類別。讓我們在表單類別中定義 FavListToJsonTextWithWriter方法,該方法傳回一個字串:

function TFormFavJSON.FavListToJsonTextWithWriter: string;
var
  Fav: TFavorite;
  Favs: TFavorites;
  StringWriter: TStringWriter;
  Writer: TJsonTextWriter;
begin
  Favs := FormFavMain.Favs;
  StringWriter := TStringWriter.Create();
  Writer := TJsonTextWriter.Create(StringWriter);
  try
    Writer.Formatting := TJsonFormatting.Indented;
    Writer.WriteStartObject;
    Writer.WritePropertyName('Favorites');
    Writer.WriteStartArray;
    for Fav in Favs do
    begin
      Writer.WriteStartObject;
      Writer.WritePropertyName('URL');
      Writer.WriteValue(Fav.URL);
      Writer.WritePropertyName('Caption');
      Writer.WriteValue(Fav.Caption);
      Writer.WriteEndObject;
    end;
    Writer.WriteEndArray;
    Writer.WriteEndObject;
    Result := StringWriter.ToString;
  finally
    Writer.Free;
    StringWriter.Free;
  end;
end;

程式碼解密:

  1. 初始化寫入器:首先,建立一個 TStringWriter 和一個 TJsonTextWriter,用於寫入JSON內容。
  2. 設定格式:將 Writer.Formatting 設定為 TJsonFormatting.Indented,以產生縮排格式的JSON。
  3. 寫入JSON結構:使用 WriteStartObject, WritePropertyName, WriteStartArray, 和 WriteValue 等方法逐步寫入JSON結構和資料。
  4. 迴圈處理:遍歷每個 TFavorite 物件,寫入其 URLCaption
  5. 結束寫入:關閉所有開啟的JSON結構。
  6. 取得結果:將 StringWriter 中的內容轉換為字串並傳回。
  7. 資源釋放:釋放 WriterStringWriter

使用 TJsonTextWriter 的方法比DOM方法更冗長,但它不會分配臨時物件,使程式碼更具可讀性,並且可以輕易預覽最終生成的JSON內容。

圖表翻譯:

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Delphi 使用 TStreamWriter TStreamReader 處理文字與 JSON 檔

package "物件導向程式設計" {
    package "核心概念" {
        component [類別 Class] as class
        component [物件 Object] as object
        component [屬性 Attribute] as attr
        component [方法 Method] as method
    }

    package "三大特性" {
        component [封裝
Encapsulation] as encap
        component [繼承
Inheritance] as inherit
        component [多型
Polymorphism] as poly
    }

    package "設計原則" {
        component [SOLID] as solid
        component [DRY] as dry
        component [KISS] as kiss
    }
}

class --> object : 實例化
object --> attr : 資料
object --> method : 行為
class --> encap : 隱藏內部
class --> inherit : 擴展功能
inherit --> poly : 覆寫方法
solid --> dry : 設計模式

note right of solid
  S: 單一職責
  O: 開放封閉
  L: 里氏替換
  I: 介面隔離
  D: 依賴反轉
end note

@enduml

此圖示呈現了生成JSON的主要步驟,從初始化變數到輸出最終的JSON字串。