2014-04-21 23 views
6

Jestem pewien, że wszyscy znamy i prawdopodobnie używamy mnóstwa kodu dostarczonego w książkach, Internecie, itp. Do czytania pliku przy użyciu C#. Coś tak prostego jak ...Zaawansowane czytanie pliku

StringBuilder fiContents = new StringBuilder(); 
using (StreamReader fi = new StreamReader(@"C:\a_file.txt")) 
{ 
    while (!fi.EndOfStream) 
    { 
     fiContents.Append(fi.ReadLine); 
    } 
} 

A może coś tak krótkie jak ...

using (StreamReader fi = new StreamReader(@"C:\a_file.txt")) 
    fiContents.Append(fi.ReadToEnd()); 

Teraz chodźmy Super Saiyan na chwilę i zrobić naprawdę wymyślnych rzeczy jak mają BackgroundWorker który pozwoli pokazujemy obraz ładujący (to, czego użyję), dostarczę licznik czasu procesu lub ProgressBar.

public void ReadFile(string filename) 
{ 
    BackgroundWorker procFile = new BackgroundWorker(); 
    // Progress 1: If we want to show the progress we need to enable the following property 
    // procFile.WorkerReportsProgress = true; 

    profile.DoWork += new DoWorkEventHandler((object obj, DoWorkEventArgs ev) => 
    { 
     StringBuilder fiContents = new StringBuilder(); 

     using (StreamReader fi = new StreamReader(filename)) 
     { 
      while (!fi.EndOfStream) 
      { 
       // Progress 2: Report the progress, this will be dealt with by the respective handler (below). 
       // procFile.ReportProgress((int)(fi.BaseStream.Length/fi.BaseStream.Position)/100); 

       fiContents.Append(fi.ReadLine); 
      } 
     } 

     ev.Result = fiContents; 
    } 

    /* Progress 3: The handler below will take care of updating the progress of the file as it's processed. 
    procFile.ProgressChanged += new ProgressChangedEventHandler((object obj, ProgressChangedEventArgs ev) => 
    { 
     // Progress 4: Do something with the value, such as update a ProgressBar. 
     // .... 
    } 
    */ 

    procFile.RunWorkerCompleted += new RunWorkerCompletedEventHandler((object obj, RunWorkerCompletedEventArgs ev) => 
    { 
     // Do something with the result (ev.Result), bearing in mind, it is a StringBuilder and the ev.Result is an object. 
     StringBuilder result = ev.Result as StringBuilder; 

     // .... 
    } 
} 

+++++ +++++ +++++ +++++

Czas rzeczywisty pytanie ... Powyższy była rozgrzewka i pokazać obecny poziom zrozumienia, więc nie mam do czynienia z nimi jako potencjalnymi odpowiedziami.

Jestem prawie robi ostatni przykład kodu podany powyżej (tj. Przy użyciu BackgroundWorker) i wyrzucając zawartość tego, co czyta się do RichTextBox. Proste rzeczy naprawdę.

Problem, z jakim mam do czynienia, to przetwarzanie dużych plików (np. ~ 222 MB). Przypadek polegający na zrobieniu pliku .txt, przeczytaniu go, wypchnięciu jego wyniku za pomocą StringBuilder do RichTextBox. Nie można załadować pliku, otrzymuję numer OutOfMemoryException. Jednym ze sposobów obejścia tego, co zajmuje znaczną ilość (i wciąż nie jest ładowany plik), jest iterowanie ciągu znaków i dodawanie każdego znaku (jako char) z pliku StringBuilder.

Zawsze używałem najbardziej podstawowych i najprostszych sposobów czytania plików (takich jak powyższe przykłady), ale czy ktoś ma jakieś wskazówki, jak poprawić to? Sposoby przetwarzania bardzo dużych plików? itp.

Nawet jako element dyskusji, chętnie przyjmuję Twoje pomysły.

+++++ +++++ +++++ +++++

Edycja 1 (@TaW) wyjątek został wyrzucony gdy próbuje umieścić string do RichTextBox ...

FileProcessing.RunWorkerCompleted += new RunWorkerCompletedEventArgs((object obj, RunWorkerCompletedEventArgs e) => 
{ 
    // 'Code' is the RichTextBox in question... 

    Code.Text = ""; 

    if (e.Result is StringBuilder) 
    { 
     Code.Text = (e.Result as StringBuilder).ToString(); 
    } 
} 
+0

Osobiście używam tylko 'File.ReadAllText (filename)' ale jestem leniwy. – Will

+0

Krótka odpowiedź brzmi, że aby załadować plik, który jest zbyt duży dla pamięci, po prostu nie można załadować go wszystkie naraz. Obciążanie tylko części pliku, która obecnie jest widoczna w przewijanym sterowaniu, jest powszechnym rozwiązaniem. –

+1

Odczytanie pliku o wielkości 200 MB powinno zająć tak mało czasu, że pasek postępu i pracownik w tle będą przesadne. –

Odpowiedz

0

Czy próbował MemoryMapped,
jest całkiem użyteczne lib do przenoszenia dużych plików

2

Czy istnieje ograniczenie masz, że wymaga, aby u se a RichTextBox jako kontrola wyświetlania twoich treści? Ta kontrola nie jest zwirtualizowana i spowoduje problemy z wydajnością (i przez jej wygląd).

Istnieje rodzina o numerach document viewing controls, które są lepiej zaprojektowane do wyświetlania dużych dokumentów. W zależności od twoich potrzeb istnieją różne kontrolki (naprawione, przepływające przez stronę lub przewijanie). Ponadto można wyszukiwać, drukować, powiększać i kilka innych funkcji, które są często przydatne do wyświetlania dużych dokumentów.

+0

Aktualnie pracuję nad edytorem skryptów (z podświetlaniem i intelli-sense), który jest teraz kompletny i wymaga RichTextBox, dzięki czemu mogłem osiągnąć wyróżnienie i inne funkcje. Będą więc zwykłymi plikami tekstowymi. – user1092809

0

nie chodzi o czytanie zaawansowane, ale o trafienie limitów wydajności (WinForm) kontrolek. Może uda się go uruchomić w WPF, ale w WinForm ani RichTextBox, ani TextBox nie może pomieścić tak dużej ilości linii/tekstu.

Radzę przeprojektować to, aby przedstawić dane użytkownikom w mniejszych porcjach. Nie chodzi o to, że chcieliby przewinąć ponad 100 000 linii. Przetwarzanie ich w pamięci nie stanowi problemu; tutaj 200 MB nie jest duże; możesz na przykład łatwo wyszukać w nim w pamięci itd.

+0

Pytanie zadane przeze mnie, gdy zadawano mi problem (który faktycznie był ograniczeniem kontroli WinForm), było dalszymi technikami w plikach I/O z C# i dyskusją. Stąd, dlaczego dostarczyłem wiele przykładów kodu, aby pokazać niektóre z technik, które znam i prawdopodobnie to, czego używa większość innych. Całkowicie zgadzam się z drugą kwestią. – user1092809