現實數據常見:日誌文件、EDI 報文、銀行對賬單等**單文件混合多種記錄結構**。例如:
核心挑戰:逐行識別格式 → 動態切換解析器配置 → 正確提取字段。
Microsoft.VisualBasic.FileIO.TextFieldParser雖在 `Microsoft.VisualBasic` 命名空間,**C# 完全可用** (引用 `Microsoft.VisualBasic.dll`)。核心能力:
TextFieldType:`FixedWidth` / `Delimited`FieldWidths / `SetFieldWidths()`:固定寬度字段寬度數組Delimiters / `SetDelimiters()`:分隔符數組PeekChars(n):不移動指針預讀前 n 字符 (識別記錄類型關鍵)ReadFields():按當前配置解析當前行,返回 `string[]`MalformedLineException:格式錯誤行異常using Microsoft.VisualBasic.FileIO;
using System;
using System.Windows.Forms; // 假設 WinForms 綁定 DataGridView
public void ParseMixedFormatFile(string filePath) {
// 定義三種格式配置
int[] fmtCK = { 5, 10, -1 }; // 固定寬度
int[] fmtPB = { 6, 10, 17, -1 }; // 固定寬度
string[] fmtSP = { "," }; // 逗號分隔
// 清空目標表格
dataGridViewCK.Rows.Clear();
dataGridViewPB.Rows.Clear();
dataGridViewSP.Rows.Clear();
using (var parser = new TextFieldParser(filePath)) {
parser.TrimWhiteSpace = false; // 固定寬度模式通常保留空白
while (!parser.EndOfData) {
try {
// 1. 預讀前 2 字符識別類型
string recordType = parser.PeekChars(2);
// 2. 根據類型動態配置解析器
switch (recordType) {
case "CK":
parser.TextFieldType = FieldType.FixedWidth;
parser.FieldWidths = fmtCK; // 或 parser.SetFieldWidths(fmtCK);
break;
case "PB":
parser.TextFieldType = FieldType.FixedWidth;
parser.FieldWidths = fmtPB;
break;
case "SP":
parser.TextFieldType = FieldType.Delimited;
parser.Delimiters = fmtSP; // 或 parser.SetDelimiters(fmtSP);
break;
default:
parser.ReadLine(); // 跳過未知行
continue;
}
// 3. 解析當前行
string[] fields = parser.ReadFields();
// 4. 分發到對應 DataGridView
switch (recordType) {
case "CK": dataGridViewCK.Rows.Add(fields); break;
case "PB": dataGridViewPB.Rows.Add(fields); break;
case "SP": dataGridViewSP.Rows.Add(fields); break;
}
}
catch (MalformedLineException ex) {
MessageBox.Show($"第 {ex.Message} 行格式錯誤,已跳過。");
// parser.ErrorLine 可獲取原始錯誤行內容
}
}
}
// 可選:排序各表格
dataGridViewCK.Sort(dataGridViewCK.Columns[0], ListSortDirection.Ascending);
dataGridViewPB.Sort(dataGridViewPB.Columns[0], ListSortDirection.Ascending);
dataGridViewSP.Sort(dataGridViewSP.Columns[0], ListSortDirection.Ascending);
}
PeekChars 非破壞性預讀解析器內部指針**不前進**,允許重複檢查或配置後再讀取。這是處理混合格式的核心。
TextFieldType 與寬度/分隔符同一 `TextFieldParser` 實例可在循環中反覆修改配置,**下一行 `ReadFields()` 使用新配置**。
最後一字段寬度 `-1` 表示「讀取剩餘所有字符直到行尾」。
private void Form_Load(object sender, EventArgs e) {
// 初始化三個 DataGridView 列
SetupGrid(dataGridViewCK, new[] { "類別編號", "類別名稱", "說明" });
SetupGrid(dataGridViewPB, new[] { "產品編號", "產品名稱", "單位數量", "單價" });
SetupGrid(dataGridViewSP, new[] { "貨運公司編號", "貨運公司名稱", "電話" });
}
private void SetupGrid(DataGridView dgv, string[] columns) {
dgv.ColumnHeadersVisible = true;
dgv.ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle {
BackColor = Color.Beige, Font = new Font("Verdana", 9, FontStyle.Bold)
};
dgv.ColumnCount = columns.Length;
for (int i = 0; i < columns.Length; i++)
dgv.Columns[i].Name = columns[i];
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
}
private void btnParse_Click(object sender, EventArgs e) {
ParseMixedFormatFile(@"Text\多格式文本文件.txt");
}
| 方案 | 混合格式支持 | CSV 標準合規 | 內存佔用 | 易用性 |
|---|---|---|---|---|
| TextFieldParser | ✅ 優秀 (PeekChars+動態配置) | ✅ 完整支持 | 流式 (低) | 中等 (需 COM 引用) |
| CsvHelper (NuGet) | ❌ 單一格式 | ✅ 完整 | 流式 | ✅ 極佳 (強類型映射) |
| File.ReadLines + Split | ✅ 手工實現 | ❌ 易錯 (引號/換行) | 流式 | 簡單但易錯 |
| Regex 逐行匹配 | ✅ 靈活 | 視寫法而定 | 流式 | 複雜難維護 |