除了自定义(字符串)分隔符之外,使用StreamReader.ReadLine()
方法的功能的最佳方式是什么?
我想做一些类似的事情:
String text;
while((text = myStreamReader.ReadUntil("my_delim")) != null)
{
Console.WriteLine(text);
}
我试着用Peek()
和StringBuilder
做我自己的,但是效率太低了。我正在寻找建议或可能的开源解决方案。
谢谢。
编辑
我应该早点澄清这一点……我已经看过this answer了,然而,我不希望将整个文件读入内存。
发布于 2012-03-28 02:18:45
我想我应该发布我自己的解决方案。它似乎工作得很好,代码也相对简单。请随时发表评论。
public static String ReadUntil(this StreamReader sr, String delim)
{
StringBuilder sb = new StringBuilder();
bool found = false;
while (!found && !sr.EndOfStream)
{
for (int i = 0; i < delim.Length; i++)
{
Char c = (char)sr.Read();
sb.Append(c);
if (c != delim[i])
break;
if (i == delim.Length - 1)
{
sb.Remove(sb.Length - delim.Length, delim.Length);
found = true;
}
}
}
return sb.ToString();
}
发布于 2012-03-26 23:09:51
这段代码适用于任何字符串分隔符。
public static IEnumerable<string> ReadChunks(this TextReader reader, string chunkSep)
{
var sb = new StringBuilder();
var sepbuffer = new Queue<char>(chunkSep.Length);
var sepArray = chunkSep.ToCharArray();
while (reader.Peek() >= 0)
{
var nextChar = (char)reader.Read();
if (nextChar == chunkSep[sepbuffer.Count])
{
sepbuffer.Enqueue(nextChar);
if (sepbuffer.Count == chunkSep.Length)
{
yield return sb.ToString();
sb.Length = 0;
sepbuffer.Clear();
}
}
else
{
sepbuffer.Enqueue(nextChar);
while (sepbuffer.Count > 0)
{
sb.Append(sepbuffer.Dequeue());
if (sepbuffer.SequenceEqual(chunkSep.Take(sepbuffer.Count)))
break;
}
}
}
yield return sb.ToString() + new string(sepbuffer.ToArray());
}
免责声明:
我对此做了一些测试,实际上比ReadLine
方法慢,但我怀疑这是因为ReadLine
方法中可以避免的入队/出队/序列相等调用(因为分隔符始终是\r\n
)。
再说一次,我做了一些测试,它应该可以工作,但不要认为它是完美的,请随意更正它。;)
发布于 2012-03-26 23:28:36
这是我在需要的地方使用的一个简单的解析器(通常如果流不是最重要的,只读和.Split做的工作),不是太优化,但应该工作得很好:
(它更像是一种Split方法--下面有更多注释)
public static IEnumerable<string> Split(this Stream stream, string delimiter, StringSplitOptions options)
{
var buffer = new char[_bufffer_len];
StringBuilder output = new StringBuilder();
int read;
using (var reader = new StreamReader(stream))
{
do
{
read = reader.ReadBlock(buffer, 0, buffer.Length);
output.Append(buffer, 0, read);
var text = output.ToString();
int id = 0, total = 0;
while ((id = text.IndexOf(delimiter, id)) >= 0)
{
var line = text.Substring(total, id - total);
id += delimiter.Length;
if (options != StringSplitOptions.RemoveEmptyEntries || line != string.Empty)
yield return line;
total = id;
}
output.Remove(0, total);
}
while (read == buffer.Length);
}
if (options != StringSplitOptions.RemoveEmptyEntries || output.Length > 0)
yield return output.ToString();
}
...and如果需要,可以简单地切换到字符分隔符,只需替换
while ((id = text.IndexOf(delimiter, id)) >= 0)
...with
while ((id = text.IndexOfAny(delimiters, id)) >= 0)
(用id++
代替id+=
和一个签名this Stream stream, StringSplitOptions options, params char[] delimiters
)
...also删除空等。
希望能有所帮助
https://stackoverflow.com/questions/9873097
复制相似问题