首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 利用資料庫 Blob 欄位實作檔案打包/解包:TFileStream 與 TBlobField 串流操作完整範例

     編輯:Delphi

前言

將多個檔案打包進資料庫單一資料表的 BLOB (Binary Large Object) 欄位,利用資料庫交易、索引、備份機制管理檔案集合,是輕量級文件管理系統的經典架構。本文示範使用 TFileStream、TBlobField.LoadFromStream/SaveToStream 實作檔案匯入/匯出,並延伸壓縮加密應用。

資料庫結構設計 (Access / SQLite / Firebird 通用)

CREATE TABLE FilePackage (
  FileName   VARCHAR(255) PRIMARY KEY,  -- 檔案名 (含相對路徑)
  FileStream BLOB,                      -- 檔案二進位內容
  FileSize   BIGINT,                    -- 原始大小
  CRC32      INTEGER,                   -- 校驗和
  ModTime    TIMESTAMP,                 -- 修改時間
  Attr       INTEGER                    -- 檔案屬性
);

Delphi 介面配置

  • Edit1: TEdit — 檔案路徑輸入
  • BtnImport: TButton — 打包匯入
  • BtnExport: TButton — 解包匯出
  • ADOTable1: TADOTable — 連結 FilePackage
  • DataSource1: TDataSource — 連結 ADOTable1

核心程式碼實作

1. 匯入檔案 (打包)

procedure TForm1.BtnImportClick(Sender: TObject);
var
  FS: TFileStream;
  FilePath: string;
begin
  FilePath := Edit1.Text;
  if not FileExists(FilePath) then
    raise Exception.Create('檔案不存在: ' + FilePath);

  FS := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite);
  try
    ADOTable1.Append;
    try
      // 關鍵:TBlobField.LoadFromStream 直接將串流寫入 BLOB
      TBlobField(ADOTable1.FieldByName('FileStream')).LoadFromStream(FS);
      
      ADOTable1.FieldByName('FileName').AsString := ExtractFileName(FilePath);
      ADOTable1.FieldByName('FileSize').AsLargeInt := FS.Size;
      ADOTable1.FieldByName('ModTime').AsDateTime := FileDateToDateTime(FileAge(FilePath));
      ADOTable1.FieldByName('Attr').AsInteger := FileGetAttr(FilePath);
      // CRC32 計算略
      
      ADOTable1.Post;
    except
      ADOTable1.Cancel;
      raise;
    end;
  finally
    FS.Free;
  end;
  
  ShowMessage('匯入完成: ' + ExtractFileName(FilePath));
end;

2. 匯出檔案 (解包)

procedure TForm1.BtnExportClick(Sender: TObject);
var
  MS: TMemoryStream;
  FileName: string;
begin
  if ADOTable1.IsEmpty then
    raise Exception.Create('資料表無資料');

  ADOTable1.First; // 示範匯出第一筆,實務應遍歷或定位
  
  FileName := ADOTable1.FieldByName('FileName').AsString;
  MS := TMemoryStream.Create;
  try
    // 關鍵:TBlobField.SaveToStream 將 BLOB 讀入串流
    TBlobField(ADOTable1.FieldByName('FileStream')).SaveToStream(MS);
    MS.Position := 0;
    MS.SaveToFile(FileName);
  finally
    MS.Free;
  end;
  
  ShowMessage('匯出完成: ' + FileName);
end;

進階:批次匯入/匯出與進度回報

procedure TForm1.BatchImport(const Folder: string);
var
  SR: TSearchRec;
  FS: TFileStream;
  Total, Done: Integer;
begin
  if FindFirst(IncludeTrailingPathDelimiter(Folder) + '*.*', faAnyFile, SR) = 0 then
  try
    repeat
      if (SR.Attr and faDirectory) = 0 then
        Inc(Total);
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;

  Done := 0;
  if FindFirst(IncludeTrailingPathDelimiter(Folder) + '*.*', faAnyFile, SR) = 0 then
  try
    repeat
      if (SR.Attr and faDirectory) = 0 then
      begin
        FS := TFileStream.Create(Folder + '\' + SR.Name, fmOpenRead or fmShareDenyWrite);
        try
          ADOTable1.Append;
          TBlobField(ADOTable1.FieldByName('FileStream')).LoadFromStream(FS);
          ADOTable1.FieldByName('FileName').AsString := SR.Name;
          ADOTable1.FieldByName('FileSize').AsLargeInt := FS.Size;
          ADOTable1.Post;
          Inc(Done);
          // 更新進度條
          ProgressBar1.Position := Done * 100 div Total;
          Application.ProcessMessages;
        finally
          FS.Free;
        end;
      end;
    until FindNext(SR) <> 0;
  finally
    FindClose(SR);
  end;
end;

延伸應用:串流管道整合壓縮/加密

利用串流組合模式,在資料寫入 BLOB 前透過管道處理:

uses Zlib, IdHashMessageDigest; // 需第三方或系統單元

// 壓縮管道匯入
procedure CompressAndStore(const SourceFile: string; BlobField: TBlobField);
var
  FS: TFileStream;
  CS: TCompressionStream; // Zlib 壓縮串流
  MS: TMemoryStream;
begin
  FS := TFileStream.Create(SourceFile, fmOpenRead);
  MS := TMemoryStream.Create;
  try
    CS := TCompressionStream.Create(clMax, MS);
    try
      CS.CopyFrom(FS, 0); // 檔案 → 壓縮 → 記憶體
    finally
      CS.Free; // 必須 Free 才會寫入 Zlib 尾部資訊
    end;
    MS.Position := 0;
    BlobField.LoadFromStream(MS); // 記憶體 → BLOB
  finally
    MS.Free;
    FS.Free;
  end;
end;

// 解壓縮管道匯出
procedure ExtractAndDecompress(BlobField: TBlobField; const DestFile: string);
var
  MS: TMemoryStream;
  DS: TDecompressionStream;
  FS: TFileStream;
begin
  MS := TMemoryStream.Create;
  try
    BlobField.SaveToStream(MS); // BLOB → 記憶體
    MS.Position := 0;
    DS := TDecompressionStream.Create(MS);
    FS := TFileStream.Create(DestFile, fmCreate);
    try
      FS.CopyFrom(DS, 0); // 解壓縮 → 檔案
    finally
      FS.Free;
      DS.Free;
    end;
  finally
    MS.Free;
  end;
end;

效能與限制考量

因素建議
單一檔案大小Access 限制 ~2GB,SQLite/Firebird/PostgreSQL 支援更大。大檔案建議分塊存儲或改用檔案系統 + 資料庫存路徑
記憶體使用TMemoryStream 全載入記憶體,大檔案改用 TFileStream 做中繼或分塊讀寫
交易控制批次匯入建議 ADOConnection.BeginTrans / CommitTrans,失敗 RollbackTrans
並發存取BLOB 欄位鎖定粒度較大,高並發場景建議檔案系統 + 資料庫元資料分離

結語

TBlobField.LoadFromStream/SaveToStream 提供了極簡潔的檔案⇄資料庫串流橋樑。配合串流管道模式,可無縫整合壓縮、加密、校驗等横切關注點。對於中小型文件管理、離線資料同步、應用程式內嵌資源庫等場景,此方案開發效率高、部署簡單 (單一資料庫檔案)、維護容易。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved