2012-04-17 24 views
11

Cześć, co muszę zrobić, to śledzić pozycję linii, którą odczytuję z czytnika strumienia, kiedy mówię: reader.ReadLine() Potrzebuję znać pozycję tej linii w pliku i chcę też móc odczytać plik z pozycji, którą wcześniej śledziłem.Śledzenie pozycji linii odtwarzacza strumieniowego

Czy to możliwe? Jeśli tak, prosimy o pomoc.

pomoc jest bardzo ceniona

Z góry dzięki.

+0

Czego potrzebują tego, jak duże są pliki ... –

Odpowiedz

17

Można to zrobić jeden z trzech sposobów:

1) Napisz StreamReader. Oto dobre miejsce na rozpoczęcie: How to know position(linenumber) of a streamreader in a textfile?

2) Klasa StreamReader ma dwie bardzo ważne, ale prywatne zmienne o nazwach charPos i charLen, które są potrzebne do zlokalizowania rzeczywistej pozycji "przeczytanej", a nie tylko podstawowej pozycji strumienia. Można użyć refleksji do uzyskania wartości jak sugeruje 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) Wystarczy przeczytać całą zawartość pliku do tablicy ciągów. Coś takiego:

char[] CRLF = new char[2] { '\n', '\r' }; 
TextReader tr = File.OpenText("some path to file"); 
string[] fileLines = tr.ReadToEnd().Split(CRLF); 

Inną możliwością (wzdłuż linii sames jak # 3) jest przeczytać w liniach i przechowywać wiersz w tablicy. Jeśli chcesz przeczytać poprzednią linię, po prostu użyj tablicy.

+0

Dzięki za odpowiedzi, ale próbowałem rozwiązanie # 2, ale nie sądzę, że to daje mi aktualną pozycję/linię, którą obecnie czytam za pomocą metody streamreader.ReadLine(). A także czy istnieje sposób na rozpoczęcie czytania pliku z określonej linii/pozycji? Z góry dziękuję. – johnnie

+0

@johnnie - prawdopodobnie ustawiając BaseStream.Position = N i używając StreamReader.Read(). Myślę, że lepiej byłoby zachować własną kolekcję wierszy z pamięci podręcznej, aby móc ponownie przeczytać dowolny numer wiersza po wierszu, nie wracając do samego pliku. Może to jednak powodować problemy z pamięcią dużych plików. –

+0

to jest problem, z którym się kłamię, plik, który muszę odczytać z pewnej linii, będzie ogromnym plikiem i przeczytanie każdej linii, aby znaleźć pewną pozycję, z której muszę czytać, będzie intensywne. W związku z tym próbuję znaleźć sposób, aby uzyskać aktualną pozycję, a następnie zapisać i przeczytać go z tego miejsca. – johnnie

2

Może to pomóc

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; 
      } 
     } 
    } 

Zastosowanie:

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(); 
     } 
Powiązane problemy