在发生异常时如何使文件流重新读取一行?

How do you cause a filestream to re-read a line in the event of an exception?

我有一个流阅读器正在读取的文件流。我想 return 在发生 IOException 时将流的位置移到上一行,以尝试再次读取同一行。我试过只记录行前流的位置,然后搜索到那一点,但一定是我误解或误用了。

using (var fs = new FileStream("MyPath\linetest.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
    Console.WriteLine(fs.CanSeek);
    while (!sr.EndOfStream)
    {
        string line;
        try
        {
            var streamPosition = fs.Position;
            line = sr.ReadLine();
            if (line.StartsWith("#"))
            {
                fs.Seek(streamPosition, SeekOrigin.Begin);
                throw new IOException();
            }
            Console.WriteLine(line);
        }
        catch (IOException e)
        {
            Console.WriteLine(e.Message);
        }
    }

以防万一,当读取到以“#”开头的行时,我会抛出异常。我的 7 行测试文件中只有一行以 # 开头,所以我希望该行写在一个无限循环中,但是,当我执行它时,它会打印文件的每一行,用异常消息替换该行以。。开始 #。如果您能提供任何见解或帮助,我们将不胜感激!

你的代码进入输入文件末尾的原因是你在 fs.Position 所处的位置是 StreamReader 从 FileStream 读取到 StreamReader 的缓冲区 在那个阶段(位置 A)。这不同于 StreamReader 返回行的位置 sr.ReadLine()(位置 B)。当然,位置A总是领先于位置B。

StreamReader没有办法提供Position B,每次从什么ReadLine()returns累加计算得到这样的物理位置也不是不可以,但是想到各种encoding和EOL和物料清单代码。要做到准确并不容易。

相反,为什么你在StreamReader 解码后得不到逻辑位置?我的意思是,在这种情况下保留行号。

var row = 0;
using (var fs = new FileStream("input/sample.txt", FileMode.Open)
using (var sr = new StreamReader(fs))
{
    Console.WriteLine(fs.CanSeek);
    while (!sr.EndOfStream)
    {
        try
        {
            var line = sr.ReadLine();
            if (line.StartsWith("#"))
                throw new IOException();
            row++;
            Console.WriteLine(line);
        }
        catch (IOException e)
        {
            Console.WriteLine(e.Message);

            // Reset to the line where the exception happened
            fs.Seek(0, SeekOrigin.Begin);
            sr.DiscardBufferedData();
            for (var i = 0; i < row; i++)
                sr.ReadLine();
        }
    }
}
catch块中的

sr.DiscardBufferedData()是为了清理我开头提到的StreamReader中的缓冲区。请记住 sr.DiscardBufferedData() 会降低性能,这在 here.

中有所提及

我不明白为什么要保持文件流打开并不断得到相同的错误结果。请注意,当流打开时,程序永远不会更新文件。因此,我多留了一段代码,它可以一直读取同一行,直到该行被更正,前提是已经处理过的行从不在换行方面进行编辑。

var row = 0;
while (true)
{
    using (var fs = new FileStream("input/sample.txt", FileMode.Open))
    using (var sr = new StreamReader(fs))
    {
        for (var i = 0; i < row; i++)
            sr.ReadLine();

        try
        {
            while (!sr.EndOfStream)
            {
                var line = sr.ReadLine();
                if (line.StartsWith("#"))
                    throw new IOException();
                row++;
                Console.WriteLine(line);
            }
        }
        catch (IOException e)
        {
            Console.WriteLine(e.Message);
        }
        if (sr.EndOfStream)
            break;
    }
}

但是,无论哪种方式,从头到错误行反复阅读,即使考虑性能也不太好。在这种情况下,您应该重新考虑设计如何输入数据。