Jaki jest najszybszy sposób wczytania pliku tekstowego do zmiennej łańcuchowej?
Rozumiem, że można to zrobić na kilka sposobów, na przykład czytać poszczególne bajty, a następnie konwertować je na ciąg. Szukałem metody z minimalnym kodowaniem.
Nie jest to jednak najlepsza funkcja do użycia. Jak wskazuje Devendra D. Chavan w swojej odpowiedzi, StreamReader.ReadToEndjest bardziej wydajny.
Owen Blacker
40
@OwenBlacker Zależy to od tego, czy „najszybszy” oznacza „najmniej czasu na wykonanie” czy „najmniej czasu na zrozumienie”.
bonh
2
File.ReadAllText jest zdecydowanie najłatwiejszy w użyciu, ale jak zauważa „Devendra D. Chavan”, nie jest najszybszy. Więc jeśli czytasz małe pliki, lepszym wyborem byłoby użycie File.ReadAllText.it naprawdę zależy od tego, jak duże są pliki tekstowe, które czytasz.
Mana,
Aby odczytać z serwera, sprawdź to , mam nadzieję, że ktoś komuś pomoże.
shaijut
1
@OwenBlacker - jesteś pewien? Benchmark pokazuje, że StreamReader.ReadToEndjest bardziej wydajny niż ReadAllLines. Tego należy się spodziewać, ponieważ ten ostatni dzieli również tekst na linie. Ale mówimy o innej metodzie ReadAllText. Rzeczywiście, wspomniana odpowiedź pokazuje, że ReadAllTextpo prostu dzwonisz StreamReader.ReadToEndwewnętrznie.
Ed Avis,
169
Porównanie testów porównawczych File.ReadAllLinesvs StreamReader ReadLinez obsługą plików C #
Wyniki StreamReader jest znacznie szybszy dla dużych plików z ponad 10 000 linii, ale różnica dla mniejszych plików jest znikoma. Jak zawsze, planuj różne rozmiary plików i używaj File.ReadAllLines tylko wtedy, gdy wydajność nie jest krytyczna.
Podejście StreamReader
Jak File.ReadAllTextinni sugerują to podejście, możesz także spróbować szybciej (nie testowałem ilościowo wpływu na wydajność, ale wydaje się, że jest szybszy niż File.ReadAllText(patrz porównanie poniżej)). Różnica w wydajności będzie widoczny tylko w przypadku większych plików chociaż.
string readContents;
using (StreamReader streamReader =newStreamReader(path,Encoding.UTF8)){
readContents = streamReader.ReadToEnd();}
Porównanie File.Readxxx () vs StreamReader.Readxxx ()
Przeglądanie kodu wskazującego przez ILSpy Znalazłem następujące informacje File.ReadAllLines, File.ReadAllText.
File.ReadAllText - Wykorzystuje StreamReader.ReadToEndwewnętrznie
File.ReadAllLines - Używa również StreamReader.ReadLinewewnętrznie z dodatkowym narzutem związanym z tworzeniem List<string>powrotu jako linii odczytu i zapętlaniem do końca pliku.
Więc obie metody są dodatkową warstwą wygody zbudowany na szczycie StreamReader. Jest to widoczne w indykatywnej treści metody.
File.ReadAllText() implementacja zdekompilowana przez ILSpy
publicstaticstringReadAllText(string path){if(path ==null){thrownewArgumentNullException("path");}if(path.Length==0){thrownewArgumentException(Environment.GetResourceString("Argument_EmptyPath"));}returnFile.InternalReadAllText(path,Encoding.UTF8);}privatestaticstringInternalReadAllText(string path,Encoding encoding){string result;
using (StreamReader streamReader =newStreamReader(path, encoding)){
result = streamReader.ReadToEnd();}return result;}
ILSpy sugeruje, że File.ReadAllText()jest to po prostu opakowanie StreamReader.ReadToEnd(). Zgaduję, że dodatkowa warstwa powinna działać nieco wolniej niż StreamReader.ReadToEnd().
Devendra D. Chavan
Świetna odpowiedź. Być może trochę wyjaśnienia dla tych, którzy szukają poprawki, ale zasługuje ona na co najmniej tyle głosów, ile wybrana odpowiedź.
Sandy Gifford,
@Devendra D. Chavan: Offtopic, ale gdzie mogę znaleźć referencje lub dokumentację dla ILSpy?
Viral Jain
1
Możesz także znaleźć kod tutaj: referenceource.microsoft.com/#mscorlib/system/io/… . Nie rozumiem, dlaczego jest tak znacząca różnica prędkości, jeśli ReadAllTextjest to tylko opakowanie streamReader.ReadToEnd();?
Ta metoda otwiera plik, odczytuje każdą linię pliku, a następnie dodaje każdą linię jako element łańcucha. Następnie zamyka plik. Linia jest zdefiniowana jako sekwencja znaków, po której następuje powrót karetki ('\ r'), znak końca linii ('\ n') lub znak powrotu karetki, po którym następuje znak linii. Powstały ciąg nie zawiera zakończenia powrotu karetki i / lub przesunięcia wiersza.
Ta metoda próbuje automatycznie wykryć kodowanie pliku na podstawie obecności znaków kolejności bajtów. Formaty kodowania UTF-8 i UTF-32 (zarówno big-endian, jak i little-endian) mogą zostać wykryte.
Użyj przeciążenia metody ReadAllText (String, Encoding) podczas odczytywania plików, które mogą zawierać zaimportowany tekst, ponieważ nierozpoznane znaki mogą nie zostać poprawnie odczytane.
Ta metoda gwarantuje, że uchwyt pliku zostanie zamknięty, nawet jeśli zgłoszone zostaną wyjątki
W tym eksperymencie porównane zostaną dwie klasy. Klasa StreamReaderi FileStreamzostanie skierowana do odczytu dwóch plików 10K i 200K w całości z katalogu aplikacji.
StreamReader(VB.NET)
sr =NewStreamReader(strFileName)Do
line = sr.ReadLine()LoopUntil line IsNothing
sr.Close()FileStream(VB.NET)Dim fs AsFileStreamDim temp As UTF8Encoding =New UTF8Encoding(True)Dim b(1024)AsByte
fs =File.OpenRead(strFileName)DoWhile fs.Read(b,0, b.Length)>0
temp.GetString(b,0, b.Length)Loop
fs.Close()
Wynik
FileStreamjest oczywiście szybszy w tym teście. StreamReaderPrzeczytanie małego pliku zajmuje dodatkowe 50% więcej czasu . W przypadku dużego pliku zajęło to dodatkowe 27% czasu.
StreamReaderszczególnie szuka podziałów linii, podczas gdy FileStreamnie. To będzie stanowiło część dodatkowego czasu.
Rekomendacje
W zależności od tego, co aplikacja musi zrobić z sekcją danych, może wystąpić dodatkowe przetwarzanie, które będzie wymagało dodatkowego czasu przetwarzania. Rozważ scenariusz, w którym plik zawiera kolumny danych, a wiersze są CR/LFrozdzielane. Spowoduje StreamReaderto wyszukanie wiersza tekstu CR/LF, a następnie aplikacja wykona dodatkowe analizowanie w poszukiwaniu określonej lokalizacji danych. (Myślałeś, że String. SubString jest dostępny bez ceny?)
Z drugiej strony dane są FileStreamodczytywane we fragmentach, a proaktywny programista mógłby napisać nieco więcej logiki, aby wykorzystać strumień na swoją korzyść. Jeśli potrzebne dane znajdują się w określonych pozycjach w pliku, jest to z pewnością odpowiednia droga, ponieważ zmniejsza zużycie pamięci.
FileStream jest lepszym mechanizmem prędkości, ale wymaga większej logiki.
publicstaticvoidReadFileToEnd(){try{//provide to reader your complete text file
using (StreamReader sr =newStreamReader("TestFile.txt")){String line = sr.ReadToEnd();Console.WriteLine(line);}}catch(Exception e){Console.WriteLine("The file could not be read:");Console.WriteLine(e.Message);}}
Dla noobów, którzy uważają to za zabawne i interesujące, najszybszy sposób na odczytanie całego pliku w ciągu w większości przypadków ( zgodnie z tymi testami ) jest następujący:
using (StreamReader sr =File.OpenText(fileName)){string s = sr.ReadToEnd();}//you then have to process the string
Jednak absolutnie najszybszy odczyt pliku tekstowego wydaje się następujący:
using (StreamReader sr =File.OpenText(fileName)){string s =String.Empty;while((s = sr.ReadLine())!=null){//do what you have to here}}
Komentarz jest spóźniony, wiem, ale trochę zmieszany w testach porównawczych tutaj i na połączonej stronie. Wygląda na to, że testuje tylko prędkości odczytu i nie ładuje się do całego ciągu. Drugi fragment kodu odczytuje wiersz na raz i nie wykonuje żadnych dopisów, więc „zrób to, co musisz tutaj” musiałby mieć konstruktor ciągów lub ciąg do przechowywania danych. W tym momencie pamięć użyta do dodania większej ilości danych zmieni wyniki testu. Więc s będzie zwykle tego samego rozmiaru, zakładając plik o stałej szerokości, więc pamięć zostanie ustawiona na rozmiar linii i dane nie będą musiały być kopiowane do nowej pamięci.
Charles Byrne,
2
Możesz użyć w ten sposób
publicstaticstringReadFileAndFetchStringInSingleLine(string file){StringBuilder sb;try{
sb =newStringBuilder();
using (FileStream fs =File.Open(file,FileMode.Open)){
using (BufferedStream bs =newBufferedStream(fs)){
using (StreamReader sr =newStreamReader(bs)){string str;while((str = sr.ReadLine())!=null){
sb.Append(str);}}}}return sb.ToString();}catch(Exception ex){return"";}}
Dokonałem porównania między ReadAllText i StreamBuffer dla csv 2Mb i wydawało się, że różnica była dość niewielka, ale ReadAllText wydawał się przewodzić od czasów wymaganych do ukończenia funkcji.
Odpowiedzi:
Co powiesz na
File.ReadAllText
:źródło
StreamReader.ReadToEnd
jest bardziej wydajny.StreamReader.ReadToEnd
jest bardziej wydajny niżReadAllLines
. Tego należy się spodziewać, ponieważ ten ostatni dzieli również tekst na linie. Ale mówimy o innej metodzieReadAllText
. Rzeczywiście, wspomniana odpowiedź pokazuje, żeReadAllText
po prostu dzwoniszStreamReader.ReadToEnd
wewnętrznie.Porównanie testów porównawczych
File.ReadAllLines
vsStreamReader ReadLine
z obsługą plików C #Podejście StreamReader
Jak
File.ReadAllText
inni sugerują to podejście, możesz także spróbować szybciej (nie testowałem ilościowo wpływu na wydajność, ale wydaje się, że jest szybszy niżFile.ReadAllText
(patrz porównanie poniżej)). Różnica w wydajności będzie widoczny tylko w przypadku większych plików chociaż.Porównanie File.Readxxx () vs StreamReader.Readxxx ()
Przeglądanie kodu wskazującego przez ILSpy Znalazłem następujące informacje
File.ReadAllLines
,File.ReadAllText
.File.ReadAllText
- WykorzystujeStreamReader.ReadToEnd
wewnętrznieFile.ReadAllLines
- Używa równieżStreamReader.ReadLine
wewnętrznie z dodatkowym narzutem związanym z tworzeniemList<string>
powrotu jako linii odczytu i zapętlaniem do końca pliku.Więc obie metody są dodatkową warstwą wygody zbudowany na szczycie
StreamReader
. Jest to widoczne w indykatywnej treści metody.File.ReadAllText()
implementacja zdekompilowana przez ILSpyźródło
File.ReadAllText
?File.ReadAllText()
jest to po prostu opakowanieStreamReader.ReadToEnd()
. Zgaduję, że dodatkowa warstwa powinna działać nieco wolniej niżStreamReader.ReadToEnd()
.ReadAllText
jest to tylko opakowaniestreamReader.ReadToEnd();
?Oto dokumentacja MSDN
źródło
Spójrz na metodę File.ReadAllText ()
Kilka ważnych uwag:
źródło
string text = File.ReadAllText("Path");
masz cały tekst w jednej zmiennej łańcuchowej. Jeśli potrzebujesz każdej linii osobno, możesz użyć tego:źródło
źródło
@Cris przepraszam. To jest cytat
MSDN Microsoft
Metodologia
W tym eksperymencie porównane zostaną dwie klasy. Klasa
StreamReader
iFileStream
zostanie skierowana do odczytu dwóch plików 10K i 200K w całości z katalogu aplikacji.Wynik
FileStream
jest oczywiście szybszy w tym teście.StreamReader
Przeczytanie małego pliku zajmuje dodatkowe 50% więcej czasu . W przypadku dużego pliku zajęło to dodatkowe 27% czasu.StreamReader
szczególnie szuka podziałów linii, podczas gdyFileStream
nie. To będzie stanowiło część dodatkowego czasu.Rekomendacje
W zależności od tego, co aplikacja musi zrobić z sekcją danych, może wystąpić dodatkowe przetwarzanie, które będzie wymagało dodatkowego czasu przetwarzania. Rozważ scenariusz, w którym plik zawiera kolumny danych, a wiersze są
CR/LF
rozdzielane. SpowodujeStreamReader
to wyszukanie wiersza tekstuCR/LF
, a następnie aplikacja wykona dodatkowe analizowanie w poszukiwaniu określonej lokalizacji danych. (Myślałeś, że String. SubString jest dostępny bez ceny?)Z drugiej strony dane są
FileStream
odczytywane we fragmentach, a proaktywny programista mógłby napisać nieco więcej logiki, aby wykorzystać strumień na swoją korzyść. Jeśli potrzebne dane znajdują się w określonych pozycjach w pliku, jest to z pewnością odpowiednia droga, ponieważ zmniejsza zużycie pamięci.FileStream
jest lepszym mechanizmem prędkości, ale wymaga większej logiki.źródło
StreamReader.ReadToEnd
?cóż, najszybszym sposobem oznaczania przy możliwie najmniejszym kodzie C # jest prawdopodobnie ten:
źródło
jeśli chcesz wybrać plik z folderu Bin aplikacji, możesz spróbować śledzić i nie zapomnieć o obsłudze wyjątków.
źródło
możesz użyć :
źródło
źródło
Dla noobów, którzy uważają to za zabawne i interesujące, najszybszy sposób na odczytanie całego pliku w ciągu w większości przypadków ( zgodnie z tymi testami ) jest następujący:
Jednak absolutnie najszybszy odczyt pliku tekstowego wydaje się następujący:
Przeciwstawiony kilku innym technikom , przez większość czasu wygrywał, w tym przeciwko BufferedReader.
źródło
Możesz użyć w ten sposób
Mam nadzieję, że to ci pomoże.
źródło
możesz przeczytać tekst z pliku tekstowego do łańcucha w następujący sposób
źródło
źródło
Dokonałem porównania między ReadAllText i StreamBuffer dla csv 2Mb i wydawało się, że różnica była dość niewielka, ale ReadAllText wydawał się przewodzić od czasów wymaganych do ukończenia funkcji.
źródło