嗨,我需要做的是,当我说reader.ReadLine()
时,我要跟踪从流读取器读取的行的位置,我需要知道该行在文件中的位置,并且我也希望能够然后从我之前跟踪的位置读取文件。
这可能吗?如果是这样,请提供帮助。
非常感谢您的帮助
提前感谢。
您可以通过以下三种方式之一执行此操作:
1)编写自己的StreamReader。这是一个不错的起点:How to know position(linenumber) of a streamreader in a textfile?
2)StreamReader类有两个非常重要的但私有的变量,分别称为charPos和charLen,它们在定位实际的“读取”位置而不只是流的基础位置时是必需的。您可以使用反射来获取建议的值here
Int32 charpos = (Int32) s.GetType().InvokeMember("charPos", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField ,null, s, null); Int32 charlen= (Int32) s.GetType().InvokeMember("charLen", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField ,null, s, null); return (Int32)s.BaseStream.Position-charlen+charpos;
3)只需将整个文件读入字符串数组即可。像这样的东西:
char[] CRLF = new char[2] { '\n', '\r' }; TextReader tr = File.OpenText("some path to file"); string[] fileLines = tr.ReadToEnd().Split(CRLF);
[另一种可能性(与#3相同)是读入这些行并将其存储在数组中。当您想阅读前一行时,只需使用数组即可。
也许这可以帮助您
public class StreamLineReader : IDisposable
{
const int BufferLength = 1024;
Stream _Base;
int _Read = 0, _Index = 0;
byte[] _Bff = new byte[BufferLength];
long _CurrentPosition = 0;
int _CurrentLine = 0;
/// <summary>
/// CurrentLine number
/// </summary>
public long CurrentPosition { get { return _CurrentPosition; } }
/// <summary>
/// CurrentLine number
/// </summary>
public int CurrentLine { get { return _CurrentLine; } }
/// <summary>
/// Constructor
/// </summary>
/// <param name="stream">Stream</param>
public StreamLineReader(Stream stream) { _Base = stream; }
/// <summary>
/// Count lines and goto line number
/// </summary>
/// <param name="goToLine">Goto Line number</param>
/// <returns>Return true if goTo sucessfully</returns>
public bool GoToLine(int goToLine) { return IGetCount(goToLine, true) == goToLine; }
/// <summary>
/// Count lines and goto line number
/// </summary>
/// <param name="goToLine">Goto Line number</param>
/// <returns>Return the Count of lines</returns>
public int GetCount(int goToLine) { return IGetCount(goToLine, false); }
/// <summary>
/// Internal method for goto&Count
/// </summary>
/// <param name="goToLine">Goto Line number</param>
/// <param name="stopWhenLine">Stop when found the selected line number</param>
/// <returns>Return the Count of lines</returns>
int IGetCount(int goToLine, bool stopWhenLine)
{
_Base.Seek(0, SeekOrigin.Begin);
_CurrentPosition = 0;
_CurrentLine = 0;
_Index = 0;
_Read = 0;
long savePosition = _Base.Length;
do
{
if (_CurrentLine == goToLine)
{
savePosition = _CurrentPosition;
if (stopWhenLine) return _CurrentLine;
}
}
while (ReadLine() != null);
// GoToPosition
int count = _CurrentLine;
_CurrentLine = goToLine;
_Base.Seek(savePosition, SeekOrigin.Begin);
return count;
}
/// <summary>
/// Read Line
/// </summary>
/// <returns></returns>
public string ReadLine()
{
bool found = false;
StringBuilder sb = new StringBuilder();
while (!found)
{
if (_Read <= 0)
{
// Read next block
_Index = 0;
_Read = _Base.Read(_Bff, 0, BufferLength);
if (_Read == 0)
{
if (sb.Length > 0) break;
return null;
}
}
for (int max = _Index + _Read; _Index < max; )
{
char ch = (char)_Bff[_Index];
_Read--; _Index++;
_CurrentPosition++;
if (ch == '\0' || ch == '\n')
{
found = true;
break;
}
else if (ch == '\r') continue;
else sb.Append(ch);
}
}
_CurrentLine++;
return sb.ToString();
}
/// <summary>
/// Free resources
/// </summary>
public void Dispose()
{
if (_Base != null)
{
_Base.Close();
_Base.Dispose();
_Base = null;
}
}
}
用途:
using (StreamLineReader st = new StreamLineReader(File.OpenRead("E:\\log.txt")))
{
bool ok = st.GoToLine(1);
int count= st.GetCount(0);
string w0 = st.ReadLine();
string w1 = st.ReadLine();
string w2 = st.ReadLine();
string w3 = st.ReadLine();
}
跟踪StreamReader的实际位置(以字节为单位):
readonly static FieldInfo charPosField = typeof(StreamReader).GetField("charPos", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
readonly static FieldInfo charLenField = typeof(StreamReader).GetField("charLen", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
readonly static FieldInfo charBufferField = typeof(StreamReader).GetField("charBuffer", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
static long ActualPosition(StreamReader reader)
{
var charBuffer = (char[])charBufferField.GetValue(reader);
var charLen = (int)charLenField.GetValue(reader);
var charPos = (int)charPosField.GetValue(reader);
return reader.BaseStream.Position - reader.CurrentEncoding.GetByteCount(charBuffer, charPos, charLen-charPos);
}
不客气。