内容最初作为包含UTF8字符数据的字节数组开始。我想到了几种其他方法,如下所示。
- 将字符串加载到StringReader中,并一次读取一块
- 将字节数组转换为字符数组,并在数组内按位置访问字符
- (这个方法似乎很愚蠢,但我还是提出来了)将字节数组复制到内存流中,并使用StreamReader
substring 的主要开销在于将子字符串剪切成一个新的字符串。使用 Reflector,您可以看到这一点:
private unsafe string InternalSubString(int startIndex, int length, bool fAlwaysCopy)
{
if (((startIndex == 0) && (length == this.Length)) && !fAlwaysCopy)
{
return this;
}
string str = FastAllocateString(length);
fixed (char* chRef = &str.m_firstChar)
{
fixed (char* chRef2 = &this.m_firstChar)
{
wstrcpy(chRef, chRef2 + startIndex, length);
}
}
return str;
}
Substring()
),需要通过5个长度检查等步骤。System.Data.DataTable
会有用?如果您正在进行多次访问并解析为其他数据类型,则DataTable
对我来说更具吸引力。如果您每次只需要一个记录保留在内存中,则Dictionary<string,object>
应足以容纳一个记录(字段名必须唯一)。int.Parse()
、double.Parse()
、bool.Parse()
等方法进行自动转换。RecordParser r = new RecordParser();
r.AddField("Name", 0, typeof(string));
r.AddField("Age", 48, typeof(int));
r.AddField("SystemId", 58, typeof(Guid));
r.RecordLength(80);
Dictionary<string, object> data = r.Parse(recordString);
[RecordLength(80)]
public class MyRecord
{
[RecordFieldOffset(0)]
string Name;
[RecordFieldOffset(48)]
int Age;
[RecordFieldOffset(58)]
Guid Systemid;
}
只需遍历属性,其中可以获取PropertyInfo.PropertyType
以了解如何处理记录中的子字符串; 您可以从属性中提取偏移量和总长度; 并返回填充有数据的类的实例。 基本上,您可以使用反射来提取信息,从我的先前建议中调用RecordParser.AddField()和RecordLength()。
然后将所有内容包装成一个整洁简洁的类:
RecordParser<MyRecord> r = new RecordParser<MyRecord>();
MyRecord data = r.Parse(recordString);
甚至可以称之为r.EnumerateFile("path\to\file")
,并使用yield return
枚举语法来解析记录。
RecordParser<MyRecord> r = new RecordParser<MyRecord>();
foreach (MyRecord data in r.EnumerateFile("foo.dat"))
{
// Do stuff with record
}
你想要做的事情听起来像是一个解析任务。如果我理解正确,你正在加载一个包含多个字段及其值的巨大字符串。对于这种特定的场景,Substring 不会特别高效。对于每个字段及其值,你需要在较大的字符串中调用 Substring 并指定特定的位置和长度。这是相当大的开销。
作为替代方案,你可以实现一个简单的解析器,一次从头到尾处理你的字符串,并在单个通道中检索每个字段和值。这样的解析器不需要非常复杂...只需要一个简单的 1 字符前瞻解析器可能就足够了。你甚至可能不需要将输入进行标记化...你可以以流式方式处理它,提取一个字段,然后提取它的值,将其放入某个容器中,然后继续进行。
如果你的输入字符串比仅仅是一系列字段和值更加复杂(即结构化),那么可能需要一个更复杂的解析器。有许多工具,如 antler,提供了框架,可以为你生成语法,生成解析器,并提供一个漂亮的 API 来消耗你解析的内容。
你是如何首先读取记录的?
你是逐个字符还是逐行阅读的?
在阅读时,您可以即时处理数据,因此不需要使用子字符串。
如果必须先读取然后处理,则将其读入字符串并使用StringReader,它将允许您逐个字符或按一定数量的字符进行阅读。
yield return
语法),但我认为应该可以。 - Colin Burnett