我正在读取CSV文件的每一行,需要获取每列中的各个值.所以现在我只是使用:
values = line.Split(delimiter);
where line
是一个字符串,它包含分隔符分隔的值.
测量我的ReadNextRow
方法的性能我注意到它花了66%String.Split
,所以我想知道是否有人知道更快的方法来做到这一点.
谢谢!
string.Split的BCL实现实际上非常快,我在这里做了一些测试,试图预先形成它并不容易.
但是有一件事你可以做,那就是将它作为一个生成器来实现:
public static IEnumerableGetSplit( this string s, char c ) { int l = s.Length; int i = 0, j = s.IndexOf( c, 0, l ); if ( j == -1 ) // No such substring { yield return s; // Return original and break yield break; } while ( j != -1 ) { if ( j - i > 0 ) // Non empty? { yield return s.Substring( i, j - i ); // Return non-empty match } i = j + 1; j = s.IndexOf( c, i, l - i ); } if ( i < l ) // Has remainder? { yield return s.Substring( i, l - i ); // Return remaining trail } }
对于小字符串,上面的方法不一定比string.Split更快,但它会在找到它们时返回结果,这是懒惰评估的强大功能.如果你排长队或需要节省内存,这就是你要走的路.
上面的方法受到IndexOf和Substring的性能的限制,它执行过多的范围检查索引,并且需要更快地优化它们并实现自己的辅助方法.你可以击败string.Split性能,但它会采取切割器int-hacking.你可以在这里阅读我的帖子.
应该指出的split()
是,如果您在文件中遇到逗号,则解析CSV文件是一种可疑的方法,例如:
1,"Something, with a comma",2,3
在不知道你如何分析的情况下,我要指出的另一件事是小心分析这种低级细节.Windows/PC计时器的粒度可能会发挥作用,您可能在循环中有很大的开销,因此使用某种控制值.
话虽这么说,它split()
是为处理正则表达式而构建的,这些正则表达式显然比你需要的更复杂(而且无论如何都是处理转义逗号的错误工具).此外,split()
还会创建大量临时对象.
因此,如果你想加快它(我很难相信这部分的性能确实是一个问题)那么你想要手工完成它并且你想重用你的缓冲区对象,所以你不是经常创建对象和给予垃圾收集器的工作是清理它们.
该算法相对简单:
停在每个逗号;
当你点击引号继续,直到你达到下一组报价;
处理转义引号(即\")并且可以说是转义逗号(\,).
哦,为了让你对正则表达式的成本有所了解,有一个问题(Java不是C#,但原理是相同的),有人想用字符串替换每个第n个字符.我建议replaceAll()
在String上使用.Jon Skeet手动编码循环.出于好奇,我对两个版本进行了比较,他的数量提高了一个数量级.
所以,如果你真的想要表现,那就是时候解析了.
或者,更好的是,使用其他人的优化解决方案,如快速CSV阅读器.
顺便说一句,虽然这与Java有关,但它涉及正则表达式(通用)和replaceAll()
手动编码循环的性能:将char放入每个N个字符的java字符串中.