C#StreamReader,“ReadLine”用于自定义分隔符
获得StreamReader.ReadLine()
方法function的最佳方法是什么,但使用自定义(字符串)分隔符?
我想做的事情如下:
String text; while((text = myStreamReader.ReadUntil("my_delim")) != null) { Console.WriteLine(text); }
我试图使用Peek()
和StringBuilder
来创建自己的,但效率太低。 我正在寻找建议或可能是一个开源解决方案。
谢谢。
编辑
我应该早点澄清一下……我已经看到了这个答案 ,但是,我不想将整个文件读入内存。
我想我会发布自己的解决方案。 它似乎工作得很好,代码相对简单。 随意评论。
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(); }
此代码应适用于任何字符串分隔符。
public static IEnumerable ReadChunks(this TextReader reader, string chunkSep) { var sb = new StringBuilder(); var sepbuffer = new Queue(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
方法中的enqueue / dequeue / sequenceEqual调用可以避免(因为分隔符总是\r\n
)。
再次,我做了一些测试,它应该工作,但不要把它当作完美的,并随时纠正它。 ;)
这是我在需要的地方使用的一个简单的解析器(通常如果流式传输不是最重要的只读,而.Split完成工作),不是太优化但应该工作正常:
(它更像是一种类似斯普利特的方法 – 以及下面的更多注释)
public static IEnumerable 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(); }
…如果需要,你可以简单地切换到char分隔符
while ((id = text.IndexOf(delimiter, id)) >= 0)
…用
while ((id = text.IndexOfAny(delimiters, id)) >= 0)
(和id++
而不是id+=
和签名this Stream stream, StringSplitOptions options, params char[] delimiters
)
…也删除空等
希望能帮助到你
public static String ReadUntil(this StreamReader streamReader, String delimiter) { StringBuilder stringBuilder = new StringBuilder(); while (!streamReader.EndOfStream) { stringBuilder.Append(value: (Char) streamReader.Read()); if (stringBuilder.ToString().EndsWith(value: delimiter)) { stringBuilder.Remove(stringBuilder.Length - delimiter.Length, delimiter.Length); break; } } return stringBuilder.ToString(); }