从文本文件中读取固定宽度的记录

时间:2020-03-06 15:01:50  来源:igfitidea点击:

我有一个充满记录的文本文件,其中每个记录中的每个字段都是固定宽度。我的第一种方法是仅使用string.Substring()解析每个记录。有没有更好的办法?

例如,格式可以描述为:

<Field1(8)><Field2(16)><Field3(12)>

具有两个记录的示例文件可能类似于:

SomeData0000000000123456SomeMoreData
Data2   0000000000555555MoreData

我只想确保我不会忽略比Substring()更优雅的方式。

更新:我最终选择了类似Killersponge的正则表达式:

private readonly Regex reLot = new Regex(REGEX_LOT, RegexOptions.Compiled);
const string REGEX_LOT = "^(?<Field1>.{6})" +
                        "(?<Field2>.{16})" +
                        "(?<Field3>.{12})";

然后,我使用以下内容来访问字段:

Match match = reLot.Match(record);
string field1 = match.Groups["Field1"].Value;

解决方案

不,Substring很好。那就是它的目的。

子串对我来说听起来不错。我立即想到的唯一缺点是,这意味着每次都要复制数据,但是除非我们证明它是瓶颈,否则我不会担心。子串很简单:)

我们可以使用正则表达式来一次匹配整个记录并捕获字段,但是我认为这会过分杀了。

我们可能需要注意,如果未在行尾填充空格以填充该字段,那么子字符串将无法工作,而无需花太多时间去弄清楚要读取的行数。当然,这仅适用于最后一个字段:)

使用FileHelpers。

例子:

[FixedLengthRecord()] 
public class MyData
{ 
  [FieldFixedLength(8)] 
  public string someData; 

  [FieldFixedLength(16)] 
  public int SomeNumber; 

  [FieldFixedLength(12)] 
  [FieldTrim(TrimMode.Right)]
  public string someMoreData;
}

然后,就这么简单:

var engine = new FileHelperEngine<MyData>(); 

// To Read Use: 
var res = engine.ReadFile("FileIn.txt"); 

// To Write Use: 
engine.WriteFile("FileOut.txt", res);

不幸的是,CLR开箱即用仅为此提供子字符串。

CodeProject上的某人使用属性定义字段创建了一个自定义解析器,我们可能想看看。

我们可以为固定格式的文件设置ODBC数据源,然后像访问其他任何数据库表一样对其进行访问。
这具有一个额外的优点,即在某人决定在中间添加一个额外字段的那个重要日子里,文件格式的特定知识不会编译到代码中。