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

C# RichTextBox 內容存入 SQL Server:RTF 文字與圖片完整保存讀取

     編輯:關於C語言

前言

`RichTextBox` 內容包含文字、字型、顏色、圖片、超連結等豐富格式,儲存為 **RTF (Rich Text Format)** 字串可完整保真。SQL Server 使用 `VARBINARY(MAX)` / `IMAGE` (舊) 欄位儲存 RTF 二進位資料。本文展示完整存取流程、編碼處理、大資料分塊讀寫與現代 ORM 寫法。

資料表結構


CREATE TABLE Documents (
    Id INT IDENTITY PRIMARY KEY,
    Title NVARCHAR(200),
    Content VARBINARY(MAX) NOT NULL, -- 儲存 RTF 二進位
    CreatedAt DATETIME2 DEFAULT SYSUTCDATETIME()
);

ADO.NET 完整存取實作

1. 存檔 (RichTextBox → RTF → Byte[] → DB)


public void SaveDocument(string title, RichTextBox rtb)
{
    // 1. 取得 RTF 字串 (含格式、圖片 Base64 內嵌)
    string rtf = rtb.Rtf; // 例如: {\rtf1\ansi\deff0 {\fonttbl...} 內容...}

    // 2. 轉換為 Byte[] (指定編碼,預建議 UTF-8)
    byte[] rtfBytes = Encoding.UTF8.GetBytes(rtf);

    // 3. 寫入資料庫
    const string sql = "INSERT INTO Documents(Title, Content) VALUES(@Title, @Content)";
    using (var conn = new SqlConnection(_connStr))
    using (var cmd = new SqlCommand(sql, conn))
    {
        cmd.Parameters.Add("@Title", SqlDbType.NVarChar, 200).Value = title;
        cmd.Parameters.Add("@Content", SqlDbType.VarBinary, -1).Value = rtfBytes; // -1 = MAX
        conn.Open();
        cmd.ExecuteNonQuery();
    }
}

2. 讀取 (DB → Byte[] → RTF → RichTextBox)


public void LoadDocument(int id, RichTextBox rtb)
{
    const string sql = "SELECT Content FROM Documents WHERE Id=@Id";
    using (var conn = new SqlConnection(_connStr))
    using (var cmd = new SqlCommand(sql, conn))
    {
        cmd.Parameters.Add("@Id", SqlDbType.Int).Value = id;
        conn.Open();
        var result = cmd.ExecuteScalar();
        if (result == null || result == DBNull.Value) return;

        byte[] rtfBytes = (byte[])result;
        // 解碼為字串 (必須與存檔編碼一致)
        string rtf = Encoding.UTF8.GetString(rtfBytes);
        
        // 指派給 RichTextBox (自動解析 RTF)
        rtb.Rtf = rtf;
    }
}

大檔案分塊讀寫 (避免記憶體爆炸)

若 RTF 超過數 MB,建議使用 `SqlDataReader.GetBytes` 分塊讀取,`SqlCommand` 配合 `UPDATETEXT` 或 `FILESTREAM` 分塊寫入。現代 SQL Server 建議直接使用 **`FILESTREAM`** 或 **`FileTable`** 儲存大型文件,資料庫僅存路徑/指標。

分塊讀取範例


public string LoadRtfChunked(int id)
{
    const string sql = "SELECT Content FROM Documents WHERE Id=@Id";
    using (var conn = new SqlConnection(_connStr))
    using (var cmd = new SqlCommand(sql, conn))
    {
        cmd.Parameters.Add("@Id", SqlDbType.Int).Value = id;
        conn.Open();
        using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
        {
            if (!reader.Read()) return null;
            
            const int BufferSize = 8192;
            byte[] buffer = new byte[BufferSize];
            long totalBytes = 0;
            using (var ms = new MemoryStream())
            {
                long offset = 0;
                int read;
                while ((read = (int)reader.GetBytes(0, offset, buffer, 0, BufferSize)) > 0)
                {
                    ms.Write(buffer, 0, read);
                    offset += read;
                    totalBytes += read;
                }
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }
    }
}

編碼陷阱與最佳實踐

問題原因解決
中文亂碼存檔用 UTF-8,讀取用 Default (ANSI)**統一指定 `Encoding.UTF8`** 存讀雙向
RTF 截斷欄位型別用 `VARBINARY(1000)` 而非 `MAX`欄位定義 `VARBINARY(MAX)`
圖片不顯示RTF 內嵌圖片為 Base64,過大超過欄位/參數限制確認 `VarBinary, -1`;大圖片改檔案儲存 + RTF 存路徑
換行消失RTF 使用 `\par` `\line`,非 `\n`信任 `rtb.Rtf` 原生輸出,勿手工組裝

現代 ORM 寫法

Entity Framework Core


// 實體
public class Document
{
    public int Id { get; set; }
    public string Title { get; set; }
    public byte[] Content { get; set; } // 對應 VARBINARY(MAX)
}

// DbContext
public class AppDbContext : DbContext
{
    public DbSet Documents { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .Property(d => d.Content)
            .HasColumnType("VARBINARY(MAX)");
    }
}

// 存檔
public async Task SaveAsync(string title, string rtf)
{
    var doc = new Document { Title = title, Content = Encoding.UTF8.GetBytes(rtf) };
    _context.Documents.Add(doc);
    await _context.SaveChangesAsync();
}

// 讀取
public async Task LoadRtfAsync(int id)
{
    var doc = await _context.Documents.FindAsync(id);
    return doc?.Content != null ? Encoding.UTF8.GetString(doc.Content) : null;
}

Dapper


public async Task SaveAsync(string title, string rtf)
{
    const string sql = "INSERT INTO Documents(Title, Content) VALUES(@Title, @Content)";
    await _conn.ExecuteAsync(sql, new { Title = title, Content = Encoding.UTF8.GetBytes(rtf) });
}

public async Task LoadRtfAsync(int id)
{
    const string sql = "SELECT Content FROM Documents WHERE Id=@Id";
    byte[] bytes = await _conn.ExecuteScalarAsync(sql, new { Id = id });
    return bytes != null ? Encoding.UTF8.GetString(bytes) : null;
}

替代方案:檔案系統 + 資料庫指標

若文件巨大 (含高解析度圖片),建議:

  1. RTF 另存為 `.rtf` 檔案 (或轉 PDF/HTML)。
  2. 資料表存 `FilePath` (相對路徑) + `FileHash` (去重) + `FileSize`。
  3. 啟用 SQL Server `FILESTREAM` / `FileTable` 獲得交易一致性 + 檔案流存取。

總結

**`rtb.Rtf` 取得/設定 RTF 字串 + `Encoding.UTF8.GetBytes/GetString` + `VARBINARY(MAX)`** 是核心模式。注意編碼一致性、大檔分塊/檔案化策略。現代專案優先用 EF Core/Dapper 簡化 ADO.NET 樣板,大文件改用 `FILESTREAM` 或物件儲存 (MinIO/Azure Blob) + 資料庫存 URI。

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