如何知道文本文件中流读取器的位置(行号)?
一个例子(这可能不是现实生活中的,但为了表达我的观点):
public void StreamInfo(StreamReader p)
{
string info = string.Format(
"The supplied streamreaer read : {0}\n at line {1}",
p.ReadLine(),
p.GetLinePosition()-1);
}
GetLinePosition
这里是streamreader的一个想象的扩展方法。 这可能吗?
当然我可以自己数数,但这不是问题。
an example (that might not be real life, but to make my point) :
public void StreamInfo(StreamReader p)
{
string info = string.Format(
"The supplied streamreaer read : {0}\n at line {1}",
p.ReadLine(),
p.GetLinePosition()-1);
}
GetLinePosition
here is an imaginary extension method of streamreader.
Is this possible?
Of course I could keep count myself but that's not the question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我在寻找类似问题的解决方案时遇到了这篇文章,我需要在特定行中寻找 StreamReader。 我最终创建了两个扩展方法来获取和设置 StreamReader 上的位置。 它实际上并不提供行号计数,但在实践中,我只是抓取每个 ReadLine() 之前的位置,如果该行感兴趣,那么我保留起始位置以供稍后设置像这样回到这一行:
重要的部分:
这对我来说效果很好,并且取决于您对使用反射的容忍度它认为这是一个相当简单的解决方案。
注意事项:
(ASCII)
。I came across this post while looking for a solution to a similar problem where I needed to seek the StreamReader to particular lines. I ended up creating two extension methods to get and set the position on a StreamReader. It doesn't actually provide a line number count, but in practice, I just grab the position before each
ReadLine()
and if the line is of interest, then I keep the start position for setting later to get back to the line like so:and the important part:
This works quite well for me and depending on your tolerance for using reflection It thinks it is a fairly simple solution.
Caveats:
(ASCII)
.StreamReader.ReadLine()
method and while a brief review of the source for StreamReader seems to indicate this will still work when using the other read methods, I have not really tested that scenario.不,不太可能。 “行号”的概念基于已读取的实际数据,而不仅仅是位置。 例如,如果您要将读取器 Seek() 到任意位置,它实际上不会读取该数据,因此它无法确定行号。
做到这一点的唯一方法就是自己跟踪它。
No, not really possible. The concept of a "line number" is based upon the actual data that's already been read, not just the position. For instance, if you were to Seek() the reader to an arbitrary position, it's not actuall going to read that data, so it wouldn't be able to determine the line number.
The only way to do this is to keep track of it yourself.
为任何 TextReader 提供行计数包装器非常容易:
缺点(为了简洁起见):
It is extremely easy to provide a line-counting wrapper for any TextReader:
Drawbacks (for the sake of brevity):
不。
考虑一下可以使用底层流对象(可以位于任何行中的任何点)来寻找任何位置。
现在考虑一下这会对 StreamReader 保存的任何计数产生什么影响。
StreamReader 应该去找出它现在在哪一行吗?
它是否应该只保留读取的行数,而不管文件中的位置如何?
恕我直言,还有更多的问题会让这成为实施的噩梦。
No.
Consider that it's possible to seek to any poisition using the underlying stream object (which could be at any point in any line).
Now consider what that would do to any count kept by the StreamReader.
Should the StreamReader go and figure out which line it's now on?
Should it just keep a number of lines read, regardless of position within the file?
There are more questions than just these that would make this a nightmare to implement, imho.
这是一个使用 ReadLine() 方法实现 StreamReader 的人,该方法注册文件位置。
http://www.daniweb.com/forums/thread35078.html
我想应该继承自 StreamReader,然后将额外的方法以及一些属性(_lineLength + _bytesRead)添加到特殊类中:
认为代码中存在一个小错误,因为字符串的长度用于计算文件位置而不是使用实际的长度读取的字节数(缺乏对 UTF8 和 UTF16 编码文件的支持)。
Here is a guy that implemented a StreamReader with ReadLine() method that registers file position.
http://www.daniweb.com/forums/thread35078.html
I guess one should inherit from StreamReader, and then add the extra method to the special class along with some properties (_lineLength + _bytesRead):
Think there is a minor bug in the code as the length of the string is used to calculate file position instead of using the actual bytes read (Lacking support for UTF8 and UTF16 encoded files).
我来这里是为了寻找一些简单的东西。 如果您只是使用 ReadLine() 并且不关心使用 Seek() 或其他任何东西,只需创建 StreamReader 的一个简单子类
,然后以正常方式进行操作,例如从名为 file 的 FileInfo 对象中
读取
reader.LineNumber
属性。I came here looking for something simple. If you're just using ReadLine() and don't care about using Seek() or anything, just make a simple subclass of StreamReader
and then you make it the normal way, say from a FileInfo object named file
and you just read the
reader.LineNumber
property.已经就 BaseStream 提出的观点是有效且重要的。 然而,在某些情况下,您想要阅读文本并知道您在文本中的位置。 将其编写为类以使其易于重用仍然很有用。
我现在尝试写这样一个类。 它似乎工作正常,但速度相当慢。 当性能不是很重要时(它并没有那么慢,见下文),它应该没问题。
我使用相同的逻辑来跟踪文本中的位置,无论您是一次读取一个字符、一次读取一个缓冲区还是一次读取一行。 虽然我确信通过放弃它可以使性能变得更好,但它使其更容易实现......并且我希望遵循代码。
我对 ReadLine 方法(我认为这是该实现的最弱点)与 StreamReader 进行了非常基本的性能比较,差异几乎是一个数量级。 我使用我的类 StreamReaderEx 获得了 22 MB/s,但直接使用 StreamReader(在我配备 SSD 的笔记本电脑上)的速度几乎是 9 倍。 虽然这可能很有趣,但我不知道如何进行正确的阅读测试; 也许使用 2 个相同的文件,每个文件都大于磁盘缓冲区,并交替读取它们..? 至少,当我运行多次时,无论哪个类首先读取测试文件,我的简单测试都会产生一致的结果。
NewLine 符号默认为Environment.NewLine,但可以设置为长度为1 或2 的任何字符串。读者仅将此符号视为换行符,这可能是一个缺点。 至少我知道 Visual Studio 多次提示我打开的文件“具有不一致的换行符”。
请注意,我没有包含 Guard 类; 这是一个简单的实用程序类,从上下文中应该可以清楚地看出如何替换它。 您甚至可以删除它,但是您会丢失一些参数检查,因此生成的代码将远离“正确”。 例如,Guard.NotNull(s, "s") 只是检查 s 是否不为 null,如果是这样,则抛出 ArgumentNullException(参数名称为“s”,因此是第二个参数)。
废话够多了,代码如下:
The points already made with respect to the BaseStream are valid and important. However, there are situations in which you want to read a text and know where in the text you are. It can still be useful to write that up as a class to make it easy to reuse.
I tried to write such a class now. It seems to work correctly, but it's rather slow. It should be fine when performance isn't crucial (it isn't that slow, see below).
I use the same logic to track position in the text regardless if you read a char at a time, one buffer at a time, or one line at a time. While I'm sure this can be made to perform rather better by abandoning this, it made it much easier to implement... and, I hope, to follow the code.
I did a very basic performance comparison of the ReadLine method (which I believe is the weakest point of this implementation) to StreamReader, and the difference is almost an order of magnitude. I got 22 MB/s using my class StreamReaderEx, but nearly 9 times as much using StreamReader directly (on my SSD-equipped laptop). While it could be interesting, I don't know how to make a proper reading test; maybe using 2 identical files, each larger than the disk buffer, and reading them alternately..? At least my simple test produces consistent results when I run it several times, and regardless of which class reads the test file first.
The NewLine symbol defaults to Environment.NewLine but can be set to any string of length 1 or 2. The reader considers only this symbol as a newline, which may be a drawback. At least I know Visual Studio has prompted me a fair number of times that a file I open "has inconsistent newlines".
Please note that I haven't included the Guard class; this is a simple utility class and it should be obvoius from the context how to replace it. You can even remove it, but you'd lose some argument checking and thus the resulting code would be farther from "correct". For example, Guard.NotNull(s, "s") simply checks that is s is not null, throwing an ArgumentNullException (with argument name "s", hence the second parameter) should it be the case.
Enough babble, here's the code: