在发生异常时如何使文件流重新读取一行?
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;
}
}
但是,无论哪种方式,从头到错误行反复阅读,即使考虑性能也不太好。在这种情况下,您应该重新考虑设计如何输入数据。
我有一个流阅读器正在读取的文件流。我想 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;
}
}
但是,无论哪种方式,从头到错误行反复阅读,即使考虑性能也不太好。在这种情况下,您应该重新考虑设计如何输入数据。