2010-01-12 19 views
53

Czytam plik w linii po wierszu i chcę móc ponownie uruchomić odczyt, wywołując metodę Rewind().Powróć StreamReader na początek

Jak mogę manipulować moim System.IO.StreamReader i/lub jego bazowym System.IO.FileStream, aby zacząć od nowa z odczytaniem pliku?

Mam sprytny pomysł, aby użyć pliku FileStream.Seek(long, SeekOffset) do poruszania się po pliku, ale nie ma on żadnego wpływu na otaczające go System.IO.StreamReader. Mógłbym Close() i ponownie przypisać zarówno strumień, jak i odesłanie do czytnika, ale mam nadzieję, że jest lepszy sposób.

Odpowiedz

93

Trzeba szukać w strumieniu, jak ty, a następnie zadzwonić DiscardBufferedData na StreamReader. Dokumentacja here:

Edycja: Dodawanie przykładowy kod:

Stream s = new MemoryStream(); 
StreamReader sr = new StreamReader(s); 
// later... after we read stuff 
s.Position = 0; 
sr.DiscardBufferedData();  // reader now reading from position 0 
+4

Bądź ostrożny, gdy robi to na wszystkich plików, które nie są proste pliki tekstowe ANSI (czy raczej jakieś pliki, które kodowanie wstępnie kłusować). Zobacz moją odpowiedź poniżej, aby uzyskać więcej szczegółów. – Eamon

+0

Zapominasz o klauzuli using/IDisposable pattern. Nowością w .NET 4.0 jest StreamReader (stream, Encoding.UTF8, true, 1024, true) i nowy StreamWriter (stream, Encoding.UTF8, 1024, true) przezwyciężają złamany wzorzec IDisposable (zamykanie StreamReader/Writer zamyka bazowy strumień ... nawet M $ nie zawsze jest w porządku, przynajmniej na początku). Jeśli chcesz czytać ze strumienia więcej niż raz, użyj dwóch lub więcej StreamReaderów, każdy w swoich własnych klauzulach użycia (nie zagnieżdżonych w sobie). Podobnie z StreamWriter. Powinieneś bardzo rzadko wywoływać DiscardBufferedData na dokumentację. – TamusJRoyce

16

To wszystko jest dobre, jeśli BaseStream rzeczywistości może być ustawiony Position własność 0.

Jeśli nie możesz (przykładem może być HttpWebResponse strumień) dobrym rozwiązaniem byłoby skopiowanie strumienia do MemoryStream ... tam można ustawić Position na 0 i ponownie uruchomić Stream tak bardzo, jak chcesz.

14

Odpowiedź Amy będzie działać dla niektórych plików, ale w zależności od kodowania strumienia bazowego mogą pojawić się nieoczekiwane wyniki.

Na przykład, jeśli strumień ma UTF-8 i ma preambułę, to StreamReader użyje go do wykrycia kodowania, a następnie wyłączenia niektórych flag wewnętrznych, które nakazują mu wykrycie kodowania i sprawdzenie preambuły. Jeśli zresetujesz pozycję strumienia do początku, czytnik strumienia ponownie pochłonie preambułę, ale po raz drugi umieści ją na wyjściu. Nie ma publicznych metod resetowania tego stanu kodowania i stanu preambuły, więc najbezpieczniejszą rzeczą do zrobienia, jeśli potrzebujesz "przewinąć" czytnik strumienia, jest poszukiwanie strumienia bazowego na początek (lub ustawienie pozycji), jak pokazano, i utworzenie nowego StreamReadera, samo wywoływanie DiscardBufferedData() na StreamReader nie będzie wystarczające.

19

użyć tej metody:

System.IO.StreamReader reader = new System.IO.StreamReader("file.txt") 
//end of reading 
reader.DiscardBufferedData(); 
reader.BaseStream.Seek(0, System.IO.SeekOrigin.Begin); 
-1

Pytanie szuka jakiejś StreamReader.Rewind() metody. Szukasz StreamReader.BaseStream.Position = 0;, która ustawia czytnik z powrotem na początek, aby można go było ponownie przeczytać.

StreamReader sr = new StreamReader("H:/kate/rani.txt"); 

Console.WriteLine(sr.ReadToEnd()); 

sr.BaseStream.Position = 0; 

Console.WriteLine("----------------------------------"); 

while (!sr.EndOfStream) 
{ 
    Console.WriteLine(sr.ReadLine()); 
} 
+0

To nie działa dobrze dla mnie. Odczytany plik HTML był wyświetlany dwa razy po przeczytaniu pierwszego wiersza, a następnie zastosowano sugerowany reset. Być może działa w niektórych przypadkach, ale nie w moim. – JohnH

1
public long ReadList(string fileName, Action<string> action,long position=0) 
{ 
    if (!File.Exists(fileName)) return 0; 

    using (var reader = new StreamReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite),System.Text.Encoding.Unicode)) 
    { 
    if (position > 0)reader.BaseStream.Position = position; 

    while (!reader.EndOfStream) 
    { 
     action(reader.ReadLine()); 
    } 
    return reader.BaseStream.Position; 
    } 
} 
+3

Proszę podać informacje, dlaczego ten fragment kodu rozwiązuje problem opisany w pytaniu. –