Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从C调用ReadLine()后,FileStream位置已关闭#_C#_Filestream_Readline - Fatal编程技术网

C# 从C调用ReadLine()后,FileStream位置已关闭#

C# 从C调用ReadLine()后,FileStream位置已关闭#,c#,filestream,readline,C#,Filestream,Readline,我试图一次读取一个(小的ish)文件,一次读取几行,我需要返回到特定块的开头 问题是,在第一次打电话给 streamReader.ReadLine(); streamReader.BaseStream.Position属性设置为文件的结尾!现在我假设一些缓存是在后台完成的,但是我希望这个属性反映从该文件使用的I字节数。是的,该文件有多行:-) 例如,再次调用ReadLine() 我怎样才能找到第1行结束的实际位置,以便稍后返回 我只能考虑通过添加ReadLine()返回的字符串的长度来手动记账

我试图一次读取一个(小的ish)文件,一次读取几行,我需要返回到特定块的开头

问题是,在第一次打电话给

streamReader.ReadLine();
streamReader.BaseStream.Position
属性设置为文件的结尾!现在我假设一些缓存是在后台完成的,但是我希望这个属性反映从该文件使用的I字节数。是的,该文件有多行:-)

例如,再次调用
ReadLine()

我怎样才能找到第1行结束的实际位置,以便稍后返回

我只能考虑通过添加ReadLine()返回的字符串的长度来手动记账,但即使在这里,也有几个注意事项:

  • ReadLine()带出可能具有可变长度的新行字符(是“\n”?是“\r\n”?等)
  • 我不确定这是否适用于可变长度字符
…所以现在看来我唯一的选择就是重新思考如何解析文件,这样我就不必倒带了

如果有帮助,我会按如下方式打开文件:

using (var reader = new StreamReader(
        new FileStream(
                       m_path, 
                       FileMode.Open, 
                       FileAccess.Read, 
                       FileShare.ReadWrite)))
{...}

有什么建议吗?

StreamReader
不是为这种用途设计的,所以如果这是您需要的,我想您必须为
文件流编写自己的包装器,如果您需要读取行,并且需要返回到以前的块,为什么不将您读取的行存储在列表中?这应该很容易


您不应该依赖于根据字符串的长度计算字节长度——因为您提到的原因:多字节字符、换行符等。

我做过类似的实现,需要快速访问超大文本文件中的第n行

streamReader.BaseStream.Position
指向文件末尾的原因是它有一个内置的缓冲区,正如您所期望的那样

通过计算从每个
ReadLine()
调用读取的字节数进行簿记将适用于大多数纯文本文件。然而,我也遇到过这样的情况:文本文件中混合了控制字符,即不可打印的字符。计算的字节数错误,导致我的程序此后无法找到正确的位置

我的最终解决方案是自己实现行读取器。到目前为止效果很好。这应该会让您了解它的外观:

using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
    int ch;
    int currentLine = 1, offset = 0;

    while ((ch = fs.ReadByte()) >= 0)
    {
        offset++;

        // This covers all cases: \r\n and only \n (for UNIX files)
        if (ch == 10)
        {
            currentLine++;

            // ... do sth such as log current offset with line number
        }
    }
}
并返回到记录的偏移量:

using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
    fs.Seek(yourOffset, SeekOrigin.Begin);
    TextReader tr = new StreamReader(fs);

    string line = tr.ReadLine();
}

另请注意,已经存在缓冲机制
FileStream

公认答案的一个问题是,如果ReadLine()遇到异常,例如由于日志框架在您ReadLine()时临时锁定了文件,那么您将不会将该行“保存”到列表中,因为它从未返回一行。如果捕获到此异常,则无法再次重试ReadLine(),因为StreamReaders的内部状态和缓冲区与上一个ReadLine()相比发生了错误,您将只返回部分行,并且您不能忽略该断行,并在OP发现时返回到其开头

如果您想找到真正的可查找位置,那么您需要使用反射来找到StreamReaders私有变量,这些变量允许您计算它在自己的缓冲区中的位置。这里看到的格兰杰解:,应该是有效的。或者做其他相关问题中的其他答案所做的事情:创建自己的StreamReader,公开真正可查找的位置(此链接中的答案:)。这是我在处理StreamReader和seeking时遇到的唯一两个选项,出于某种原因,这两个选项决定在几乎所有情况下都完全消除查找的可能性


编辑:我使用了格兰杰的解决方案,它是有效的。只需确保按照以下顺序执行:GetActualPosition(),然后将BaseStream.Position设置为该位置,然后确保调用DiscardBufferedData(),最后可以调用ReadLine(),这样就可以从方法中给定的位置开始获取整行。

存在问题。处理BOM是一件大事。