2014-10-19 105 views
0

我正在用StreamReader读取文件的.NET应用程序中编写文件解析器。要解析的文件以标头开头,标头以"<eoh>"结尾。我想要从开始直到该字符串读取或忽略所有内容。实际数据在此之后开始。用StreamReader读取到某个字符串

该文件不是基于行的。一切只有通过这样的标记字符串进行分配。所以我不能使用ReadLine。

如何在不读取一个字符的情况下执行状态机来识别标记工作字符?我正在寻找一种方法,如StreamReader.SkipUntilAfter(string)StreamReader.ReadUntil(string)

哦,这个项目仍然使用.NET 2.0,所以在这里不需要LINQ。尽管如果有人建议使用它,我可能会解决这个问题。

+0

如果文件是基于行的,你可以使用'File.ReadLines'和LINQ(f.e。'SkipWhile','TakeWhile')。 – 2014-10-19 19:53:20

+0

您可以使用while((line = reader.ReadLine())!= null){//只读后行.Equals(“”)} – Crasher 2014-10-19 19:54:52

+0

更新的问题:它不是基于行的。标记可能出现在一行的中间。然后我已经阅读了部分数据。而StreamReader无法在任何地方寻找或寻找。 – ygoe 2014-10-19 19:57:25

回答

1

TextReader s一般已经阅读只是逐字。他们使用一个缓冲区,这样更快,但是对于StreamReader的缓冲没有什么不同,只是直到前面读取并拉动到<eoh>。出于同样的原因,直到在该标题之后跳过也没有更好的方法。绝对最佳情况将是一个内置函数,它只是在视觉上抽象出底层代码,所以这不是特别有用。

如果您因为某种原因不相信我,here's the source code

另外,值得注意的是,无论使用什么,您都必须逐个字符地查看。即使你有办法将它们拉入内存中,比较两个string也是逐个字符的操作。所以你不会保存任何东西。

就我个人而言,我只是喜欢这样的东西。它需要TextReader和结尾字符串,并读取reader,直到找到eoh。然后它返回一个bool它是否找到标记。

public bool SkipUntilAfterHeader(TextReader reader, string eoh) 
{ 
    int eohGuessIndex = 0; 
    int next; 

    while ((next = reader.Read()) != -1) 
    { 
     char c = (char)next; 

     if (c == eoh[eohGuessIndex]) 
     { 
      eohGuessIndex++; 
      if (eohGuessIndex == eoh.Length) 
      { 
       return true; 
      } 
     } 
     else 
     { 
      eohGuessIndex = 0; 
     } 
    } 

    return false; 
} 

我不确定什么.NET 2.0有或没有,所以我写了一些从头开始,可能或可能不必。但是,性能不应该受到影响。这方面的一个很好的方面是,您还可以轻松地添加一个StringBuilder以及一个out参数,该参数可以传递标头信息,以备日后使用。

然后,使用非常简单。

public void ReadFile(string path) 
{ 
    using (StreamReader reader = new StreamReader(path)) 
    { 
     if (SkipUntilAfterHeader(reader, "<eoh>")) 
     { 
      // read file 
     } 
     else 
     { 
      // corrupt file 
     } 
    } 
} 

但是,实际上,读取整个文件并仅返回相关部分可能会更容易。与可读性相比,这取决于性能有多重要。

而在经典的糟糕的形式,请注意,我没有测试 - 甚至编译 - 这一切。但即使不起作用,它也应该相对容易修复。

+0

这将工作,但按字符读取的字节比StreamReader内部的CPU密集得多。 – usr 2014-10-19 20:52:46

+0

@usr不,实际上不是。查看参考源实现['Read'](http://referencesource.microsoft.com/mscorlib/a.html#5d81175d2e6d320e)及其对['ReadLine']的实现(http://referencesource.microsoft的.com/mscorlib程序/ a.html#a4ada5f765646068)。 “ReadLine”实际上与我一样,只是更加优化一点而已。但在这里你什么也做不了。他们都在内部使用缓冲区,所以它主要只是内存读取。 'List <>'很容易做得更好,但是我选择了更多可扩展的选项。 – 2014-10-19 20:57:30

+1

您的热循环比StreamReader可以做的要少得多,因为它可以直接使用其内部缓冲区。为每个字符调用Read是你在基准测试中会注意到的。此外,列表添加和删除会增加开销。我会说你的速度比原生版慢3倍以上。 – usr 2014-10-19 21:00:56