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

C# TextFieldParser 解析多格式混合文本文件實戰

     編輯:關於C#

場景:單文件包含多種記錄格式

現實數據常見:日誌文件、EDI 報文、銀行對賬單等**單文件混合多種記錄結構**。例如:

  • 以 `CK` 開頭:固定寬度字段 (5, 10, -1 表示剩餘)
  • 以 `PB` 開頭:固定寬度字段 (6, 10, 17, -1)
  • 以 `SP` 開頭:逗號分隔 (CSV)

核心挑戰:逐行識別格式 → 動態切換解析器配置 → 正確提取字段。

關鍵類: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);
}

關鍵技術點解析

1. PeekChars 非破壞性預讀

解析器內部指針**不前進**,允許重複檢查或配置後再讀取。這是處理混合格式的核心。

2. 動態切換 TextFieldType 與寬度/分隔符

同一 `TextFieldParser` 實例可在循環中反覆修改配置,**下一行 `ReadFields()` 使用新配置**。

3. 固定寬度中的 `-1` 含義

最後一字段寬度 `-1` 表示「讀取剩餘所有字符直到行尾」。

4. 異常處理與容錯

  • `MalformedLineException`:字段數不匹配、引號不閉合等。
  • 捕獲後可記錄日誌、跳過、或嘗試修復後重試。
  • `parser.ErrorLine` 獲取原始文本,`parser.ErrorLineNumber` 獲取行號。

數據綁定 DataGridView 完整示例

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");
}

避坑指南與最佳實踐

  • ✅ **引用 `Microsoft.VisualBasic.dll`**:C# 專案右鍵添加引用 → 框架 → 勾選。
  • ✅ **編碼處理**:`TextFieldParser` 構造函數可傳 `Encoding` (默認 UTF-8),舊系統文件常需 `Encoding.GetEncoding("GB2312")`。
  • ✅ **大文件流式處理**:`TextFieldParser` 基於 `StreamReader`,**不載入整文件到內存**,適合 GB 級文件。
  • ✅ **註釋行跳過**:`parser.CommentTokens = new[] { "#", "//" }` 自動跳過註釋行。
  • ❌ **不要在 `using` 區塊外訪問 parser**:已釋放底層流。
  • 🔧 **高性能替代**:極大文件 (10GB+) 可用 `File.ReadLines` + 手工 `Substring`/`Split` 避免解析器開銷。
  • 🔧 **CSV 標準合規**:`TextFieldParser` 支持雙引號包裹、轉義引號、換行符字段等 RFC 4180 特性,優於簡單 `Split(',')`。

對比:其他解析方案

方案混合格式支持CSV 標準合規內存佔用易用性
TextFieldParser✅ 優秀 (PeekChars+動態配置)✅ 完整支持流式 (低)中等 (需 COM 引用)
CsvHelper (NuGet)❌ 單一格式✅ 完整流式✅ 極佳 (強類型映射)
File.ReadLines + Split✅ 手工實現❌ 易錯 (引號/換行)流式簡單但易錯
Regex 逐行匹配✅ 靈活視寫法而定流式複雜難維護
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved