.net 相对于其他字符串处理方法,String.Substring的速度有多快?

.net 相对于其他字符串处理方法,String.Substring的速度有多快?,.net,performance,string,.net,Performance,String,我正在使用VB.NET处理一条固定长度的长记录。最简单的选择似乎是将整个记录加载到一个字符串中,并使用子字符串按位置和长度访问字段。但在子字符串方法中似乎会有一些冗余处理,这在每次调用时都会发生。这让我怀疑使用基于流或基于数组的方法是否可以获得更好的结果 内容以包含UTF8字符数据的字节数组开始。下面列出了我想到的其他几种方法 将字符串加载到StringReader并一次读取其中的块 将字节数组转换为字符数组并按位置访问数组中的字符 (这个看起来很傻,但我会把它扔出去)将字节数组复制到内存流并使

我正在使用VB.NET处理一条固定长度的长记录。最简单的选择似乎是将整个记录加载到一个字符串中,并使用子字符串按位置和长度访问字段。但在子字符串方法中似乎会有一些冗余处理,这在每次调用时都会发生。这让我怀疑使用基于流或基于数组的方法是否可以获得更好的结果

内容以包含UTF8字符数据的字节数组开始。下面列出了我想到的其他几种方法

  • 将字符串加载到StringReader并一次读取其中的块
  • 将字节数组转换为字符数组并按位置访问数组中的字符
  • (这个看起来很傻,但我会把它扔出去)将字节数组复制到内存流并使用StreamReader

  • 这绝对是过早的优化;子字符串方法可能是完全可以接受的,即使它慢了几毫秒。但我想在编写代码之前我会问一下,看看是否有人能想出使用其他方法的理由

    子字符串的主要成本是将子字符串删除为新字符串。使用反射器,您可以看到:

    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
    对我来说更具吸引力。如果一次只需要内存中的一条记录,那么
    字典
    应该足以保存一条记录(字段名必须是唯一的)

    或者,您可以编写一个定制的泛型类,为您处理固定长度的记录读取。指示每个字段的起始索引和字段类型。字段的长度由下一个字段的开头推断(例外是可以从总记录长度推断的最后一个字段)。这些类型可以使用
    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);
    
    只需运行属性,从中可以获得
    PropertyInfo.PropertyType
    ,了解如何处理记录中的子字符串;可以从属性中提取偏移和总长度;并返回已填充数据的类实例。本质上,您可以使用反射提取信息,从我之前的建议中调用RecordParser.AddField()和RecordLength()

    然后将其全部打包成一个整洁的小课堂:

    RecordParser<MyRecord> r = new RecordParser<MyRecord>();
    MyRecord data = r.Parse(recordString);
    

    最快的方法可能是使用流技术,因为假设您可以按顺序读取每个字段,那么它只会将您需要的内容保存在内存中并保存下来。

    您首先是如何读取记录的

    你是逐字阅读还是逐行阅读

    当你阅读的时候,你可能可以在飞行中做一些事情,因此没有子串参与


    如果您必须先读取一次,然后再处理,然后再读入一个字符串并使用StringReader,它将允许您逐个字符或按多个字符进行读取。

    您尝试执行的操作听起来像是一项解析任务。如果我理解正确,您将加载一个包含多个字段及其值的巨大字符串。对于这种特殊的场景,子字符串的性能不会特别好。对于每个字段及其值,您需要在较大的字符串中调用具有特定位置和长度的子字符串。这是相当大的开销

    作为替代方案,您可以实现一个简单的解析器,从开始到结束只处理字符串一次,并在一次传递中检索每个字段和值。这样的解析器不需要非常复杂……只需一个简单的1字符前瞻解析器就可以了。您甚至可能不需要标记您的输入…您可以以流式方式处理它,提取一个字段,然后提取其值,将其粘贴到某个容器中,然后继续


    如果输入字符串比一系列字段和值(即其结构)更复杂,则可能需要更复杂的解析器。有很多工具,比如,它们提供了框架,可以为您生成语法,生成解析器,并提供一个很好的API来使用您解析的内容。

    它从UTF-8字节数组开始。这是一张没有台词的单张唱片。将整个内容读入字符串并使用StringReader进行处理是我的选择之一。这就是你的建议吗?谢谢你的建议。这就是我想知道的事情。您是否建议我创建一个列与记录格式相匹配的数据表,然后按顺序读取记录并在运行时填充数据表?这是一个有趣的建议,我没有想到。我的假设是,你有多条记录要读,同时需要多条记录在内存中。我想如果你只有一张唱片,那么一本字典就足够了,是吗?您甚至可以编写一个类来通用地处理这个问题。我将把这个注释整合到我的答案中。对不起,我想我所有的代码都是C#。我不懂VB,所以我不确定能翻译多少(即
    产生返回
    语法),但我假设它会。
    RecordParser<MyRecord> r = new RecordParser<MyRecord>();
    MyRecord data = r.Parse(recordString);
    
    RecordParser<MyRecord> r = new RecordParser<MyRecord>();
    foreach (MyRecord data in r.EnumerateFile("foo.dat"))
    {
        // Do stuff with record
    }