.net 使用StreamReader读取特定字符串

.net 使用StreamReader读取特定字符串,.net,streamreader,.net,Streamreader,我正在.NET应用程序中编写一个文件解析器,它使用StreamReader读取文件。要分析的文件以头开始,头以“结尾。我想从一开始就读取或忽略所有内容,直到字符串。实际数据在此之后开始 该文件不是基于行的。所有的一切都是由这样的标记线来标记的。所以我不能使用ReadLine 如果不一次读取一个字符并实现一个状态机来识别标记工作字符,我如何做到这一点?我特别想找一种方法,比如StreamReader.SkipUntilAfter(string)或StreamReader.ReadUntil(str

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

该文件不是基于行的。所有的一切都是由这样的标记线来标记的。所以我不能使用ReadLine

如果不一次读取一个字符并实现一个状态机来识别标记工作字符,我如何做到这一点?我特别想找一种方法,比如
StreamReader.SkipUntilAfter(string)
StreamReader.ReadUntil(string)


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

TextReader
s通常已经逐字读取了。它们使用了一个缓冲区,因此速度更快,但是
StreamReader
的缓冲区与只在
前读取并一直拉到
没有什么不同。出于同样的原因,也没有更好的方法可以跳到该标题之后。绝对最好的情况是一个内置函数,它只是直观地抽象底层代码,所以这不是特别有用

万一你不相信我,不管是什么原因

此外,值得注意的是,无论发生什么情况,你都必须逐个角色查看。即使您有办法不这样做就将它们拉入内存,比较两个
string
s也是一个逐个字符的操作。这样你就什么也救不了了

就我个人而言,我会选择这样的方式。它获取
TextReader
和标题字符串的结尾,并读取
阅读器
,直到找到
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;
}
我不确定.NET2.0有什么或没有什么,所以我从零开始写了一些东西,可能需要也可能不需要。但是性能不应该受到影响。一个很好的方面是,您还可以轻松地添加一个带有
out
参数的
StringBuilder
,该参数将传递标题信息,以防以后需要

那么,用法就相当简单了

public void ReadFile(string path)
{
    using (StreamReader reader = new StreamReader(path))
    {
        if (SkipUntilAfterHeader(reader, "<eoh>"))
        {
            // read file
        }
        else
        {
            // corrupt file
        }
    }
}
public void ReadFile(字符串路径)
{
使用(StreamReader=新StreamReader(路径))
{
if(SkipUntilAfterHeader(读卡器“”))
{
//读取文件
}
其他的
{
//损坏的文件
}
}
}
但是,实际上,读取整个文件并只返回相关部分可能更容易。这只取决于性能相对于可读性的重要性


在经典的糟糕形式中,请注意,我没有测试——甚至没有编译——这些。但是它应该相对容易修复,即使它不工作。

如果文件是基于行的,你可以使用
file.ReadLines
和LINQ(f.e.
SkipWhile
TakeWhile
)。你可以使用while((line=reader.ReadLine())!=null){//只在行之后读取。等于(“”)更新问题:它不是基于行的。标记可以出现在一条直线的中间。那么我已经读了部分数据了。而且StreamReader无法返回或查找任何位置。您不能一次读取整个文件,然后处理它吗?您的请求非常合理。这是一个任意限制,您最多只能读取一个换行符。为什么不做点别的?分叉StreamReader源代码。这是可以理解的。这可以工作,但是逐字符读取比StreamReader内部所做的要占用更多的CPU。@usr不,实际上不是。查看其实现的参考源和的实现
ReadLine
有效地做了与我相同的事情,只是稍微优化了一点。但没有什么是你不能在这里做的。它们都在内部使用缓冲区,所以大部分只是内存读取。
列表可以很容易地变得更好,但我选择了更具可扩展性的选项。您的热循环远没有StreamReader紧密,因为它可以直接使用内部缓冲区。在基准测试中,您会注意到为每个字符调用Read。此外,添加和删除列表会增加开销。我想说你的版本比本地版本慢了>=3倍。@usr很公平。你把我弄到手了。我想这只是一个例子,它应该是什么样子。我不认为有任何可行的方法可以逃避
Read
调用,而不立即阅读整个内容,这正是OP想要避免的。只要有一个持久化的索引,
列表
肯定可以做得更好,因此比较只需进行一次。但这是一种快速而肮脏的方式,表明需要发生什么。我认为你的解决方案原则上是好的。(除了现在它无法匹配“