.NET 以 Stream 抽象統一檔案、記憶體、網路等資料來源。文字檔案處理核心在於 StreamReader(讀取)與 StreamWriter(寫入),搭配 FileStream 實體檔案存取。本文完整涵蓋讀取顯示、修改儲存、列印預覽、正式列印的端到端實作。
| 類別 | 命名空間 | 用途 |
|---|---|---|
| FileStream | System.IO | 檔案位元組串流 |
| StreamReader | System.IO | 文字讀取器(編碼轉換) |
| StreamWriter | System.IO | 文字寫入器(編碼轉換) |
| StringReader | System.IO | 字串作為串流讀取(列印用) |
| PrintDocument | System.Drawing.Printing | 列印文件核心類別 |
| PrintPreviewDialog | System.Windows.Forms | 列印預覽對話框 |
| PrintDialog | System.Windows.Forms | 列印設定對話框 |
private void LoadFile(string filePath)
{
try
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (StreamReader reader = new StreamReader(fs, Encoding.Default)) // 或 Encoding.UTF8
{
reader.BaseStream.Seek(0, SeekOrigin.Begin);
richTextBox1.Text = "";
string line;
while ((line = reader.ReadLine()) != null)
{
richTextBox1.Text += line + "\n";
}
}
}
catch (Exception ex)
{
MessageBox.Show("讀取失敗:" + ex.Message);
}
}
關鍵點:using 確保資源釋放,Encoding.Default 使用系統預設編碼(中文環境為 Big5/CP950),現代專案建議統一 UTF-8。
private void SaveFile(string filePath)
{
try
{
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
using (StreamWriter writer = new StreamWriter(fs, Encoding.Default))
{
writer.BaseStream.Seek(0, SeekOrigin.Begin);
writer.Write(richTextBox1.Text);
writer.Flush();
}
MessageBox.Show("儲存成功!");
}
catch (Exception ex)
{
MessageBox.Show("儲存失敗:" + ex.Message);
}
}
FileMode.OpenOrCreate:檔案存在則開啟,不存在則建立。
private PrintDocument printDoc = new PrintDocument();
private StringReader printReader;
private void PrintPreview()
{
try
{
printReader = new StringReader(richTextBox1.Text);
PrintPreviewDialog preview = new PrintPreviewDialog();
preview.Document = printDoc;
preview.ShowDialog();
}
catch (Exception ex)
{
MessageBox.Show("預覽錯誤:" + ex.Message);
}
}
private void PrintFile()
{
PrintDialog dlg = new PrintDialog();
dlg.Document = printDoc;
printReader = new StringReader(richTextBox1.Text); // 重置讀取器
if (dlg.ShowDialog() == DialogResult.OK)
{
try
{
printDoc.Print();
}
catch (Exception ex)
{
MessageBox.Show("列印錯誤:" + ex.Message);
printDoc.PrintController.OnEndPrint(printDoc, new PrintEventArgs());
}
}
}
private void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = e.MarginBounds.Left;
float topMargin = e.MarginBounds.Top;
string line = null;
Font printFont = richTextBox1.Font;
Brush brush = Brushes.Black;
// 計算每頁行數
linesPerPage = e.MarginBounds.Height / printFont.GetHeight(g);
// 逐行列印
while (count < linesPerPage && ((line = printReader.ReadLine()) != null))
{
yPos = topMargin + count * printFont.GetHeight(g);
g.DrawString(line, printFont, brush, leftMargin, yPos, new StringFormat());
count++;
}
// 判斷是否有下一頁
e.HasMorePages = (line != null);
}
關鍵設計:printReader 為類別成員變數,跨多次 PrintPage 呼叫保持讀取位置,自動實現分頁續印。
public class TextEditorForm : Form
{
private RichTextBox richTextBox1;
private PrintDocument printDoc = new PrintDocument();
private StringReader printReader;
public TextEditorForm()
{
InitializeComponent();
printDoc.PrintPage += printDoc_PrintPage;
}
private void InitializeComponent()
{
richTextBox1 = new RichTextBox { Dock = DockStyle.Fill };
MenuStrip menu = new MenuStrip();
ToolStripMenuItem fileMenu = new ToolStripMenuItem("檔案");
fileMenu.DropDownItems.Add("開啟", null, (s,e) => OpenFile());
fileMenu.DropDownItems.Add("儲存", null, (s,e) => SaveFile());
fileMenu.DropDownItems.Add("列印預覽", null, (s,e) => PrintPreview());
fileMenu.DropDownItems.Add("列印", null, (s,e) => PrintFile());
menu.Items.Add(fileMenu);
this.Controls.Add(richTextBox1);
this.Controls.Add(menu);
this.MainMenuStrip = menu;
this.ClientSize = new Size(600, 400);
}
// ... 以上四大功能方法 ...
// ... printDoc_PrintPage 事件處理 ...
[STAThread]
static void Main()
{
Application.Run(new TextEditorForm());
}
}
| 情境 | 建議編碼 | 程式碼 |
|---|---|---|
| 現代專案/跨平台 | UTF-8 | Encoding.UTF8 |
| 繁體中文舊系統相容 | Big5 (CP950) | Encoding.GetEncoding(950) |
| 簡體中文舊系統相容 | GB2312 (CP936) | Encoding.GetEncoding(936) |
| 不確定編碼 | 偵測 BOM 或預設 UTF-8 | new StreamReader(fs, true) (detectEncodingFromByteOrderMarks) |
ReadLine() 避免一次載入整個檔案ReadLineAsync()、WriteAsync() 配合 awaitFile.ReadLines() (LINQ) 延遲執行C# 文字檔案處理建立在 Stream 抽象之上,StreamReader/StreamWriter 處理編碼轉換,PrintDocument 配合 PrintPage 事件實現分頁列印。掌握 StringReader 當列印資料來源、HasMorePages 控制分頁流程、using 確保資源釋放三大核心模式,即可開發功能完整的文字編輯器與列印功能。現代專案建議統一 UTF-8 編碼,並善用非同步 API 提升回應性。