2009-05-07 16 views
6

Bir WPF RichTextBox'a ~ 10MB aralıklı bir metin dosyası yüklemem gerekiyor, ancak geçerli kodum UI'yi donduruyor. Bir arka plan işçisini yüklemeyi yapmayı denedim, ama bu da işe yaramıyor gibi gözüküyor.C# - WPF RichTextBox içine büyük bir dosya yükleniyor?

İşte yükleme kodum. Performansını iyileştirmenin bir yolu var mı? Teşekkürler.

//works well for small files only 
    private void LoadTextDocument(string fileName, RichTextBox rtb) 
    { 
     System.IO.StreamReader objReader = new StreamReader(fileName); 

     if (File.Exists(fileName)) 
     { 
       rtb.AppendText(objReader.ReadToEnd()); 
     } 
     else rtb.AppendText("ERROR: File not found!"); 
     objReader.Close(); 
    } 






    //background worker version. doesnt work well 
    private void LoadBigTextDocument(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = sender as BackgroundWorker; 
     System.IO.StreamReader objReader = new StreamReader( ((string[])e.Argument)[0] ); 
     StringBuilder sB = new StringBuilder("For performance reasons, only the first 1500 lines are displayed. If you need to view the entire output, use an external program.\n", 5000); 

      int bigcount = 0; 
      int count = 1; 
      while (objReader.Peek() > -1) 
      { 
       sB.Append(objReader.ReadLine()).Append("\n"); 
       count++; 
       if (count % 100 == 0 && bigcount < 15) 
       { 
        worker.ReportProgress(bigcount, sB.ToString()); 

        bigcount++; 
        sB.Length = 0; 
       } 
      } 
     objReader.Close(); 
     e.Result = "Done"; 
    } 

cevap

1

Neden bir dize değişkenine katmayan (hatta belki StringBuilder kullanın) Eğer ayrıştırma bittiğinde sonra .Text özelliğine değer atamak?

+0

kod ya da saniyenin ilk blok bahsediyoruz? –

-1

Uygulamayı çok iş parçacıklı hale getirmeyi denediniz mi?

Metin dosyasının ne kadarını bir defada görmeniz gerekiyor? NET'te veya yüklemenizde tembel yükleme içine bakmak isteyebilirsiniz. C#

3

Grafiksel kontroller bu tür verileri işlemek için tasarlanmamıştır. Kontrol, büyük dizeyi işleyebilseydi bile, kontrolde neyin göründüğü, kaydırma çubuklarının pratik olarak işe yaramayacağı tüm metne kıyasla çok azdır. Metinde belirli bir çizgiyi bulmak için, kaydırıcıyı belirleyebileceği en yakın konuma taşımak zorunda kalacaksınız, ardından dakikalar boyunca bir satırda bir satır ilerleyiniz ...

Kullanıcılarınızı böyle işe yaramaz bir şey sunmak yerine verileri nasıl görüntülediğinizi tekrar düşünmelisiniz, böylece bunu kullanmak mümkün olacak şekilde yapabilirsiniz.

+3

Sormak mantıksız bir şey değil. UltraEdit'te çok GB dosyaları açmadan açabilirim. RTF değil, elbette, fakat ticari IDE'lerin çoğu, 10MB aralığındaki dosyaları makul bir şekilde ele alıyorlar - ve sadece ön formatlı formatlamayı değil, güzel renkleri elde etmek için dil sözdizimini ayrıştırmak zorunda olduklarını unutmayın. –

+1

@Richard: Evet, büyük dosyaları işleyebilen programlar var, ancak basit bir GUI denetimi yok. Böylesine büyük bir dizgiyi düzenlemek, her küçük değişiklik için 20 GB veri kopyaladığınız anlamına gelir, böylece kontrol aşırı derecede yavaşlar. Büyük dosyaları işleyen programlar, bellekte verileri temsil etmenin farklı bir yolunu kullanır. – Guffa

+0

@downvoter: Neden düşüş yok? Yanlış olduğunu düşündüğünüz şeyi açıklamıyorsanız, cevabı iyileştiremez. – Guffa

1

Daha fazla "satır" ekledikçe yavaşlamaya başladığında RichTextbox'ları kullanarak bildirimde bulundum. Eğer '\ n' eklemeden yapabilirseniz, sizin için hızlanacak. Her '\ n' öğesinin RichTextbox için yeni bir paragraf nesnesi olduğunu unutmayın.

Bu, 10 MB'lık bir dosya yükleme yöntemim. Yüklemek yaklaşık 30 saniye sürer. Kullanıcımın yüklenmesinin zaman alacağını bildirmek için bir ilerleme çubuğu iletişim kutusu kullanıyorum.

// Get Stream of the file 
fileReader = new StreamReader(File.Open(this.FileName, FileMode.Open)); 

FileInfo fileInfo = new FileInfo(this.FileName); 

long bytesRead = 0; 

// Change the 75 for performance. Find a number that suits your application best 
int bufferLength = 1024 * 75; 

while (!fileReader.EndOfStream) 
{ 
    double completePercent = ((double)bytesRead/(double)fileInfo.Length); 

    // I am using my own Progress Bar Dialog I left in here to show an example 
    this.ProgressBar.UpdateProgressBar(completePercent); 

    int readLength = bufferLength; 

    if ((fileInfo.Length - bytesRead) < readLength) 
    { 
     // There is less in the file than the lenght I am going to read so change it to the 
     // smaller value 
     readLength = (int)(fileInfo.Length - bytesRead); 
    } 

    char[] buffer = new char[readLength]; 

    // GEt the next chunk of the file 
    bytesRead += (long)(fileReader.Read(buffer, 0, readLength)); 

    // This will help the file load much faster 
    string currentLine = new string(buffer).Replace("\n", string.Empty); 

    // Load in background 
    this.Dispatcher.BeginInvoke(new Action(() => 
     { 
      TextRange range = new TextRange(textBox.Document.ContentEnd, textBox.Document.ContentEnd); 
      range.Text = currentLine; 

     }), DispatcherPriority.Normal); 
} 
+0

Bu '\ n '/ n' değil. – markwatson

+0

Siz efendim, bir şampiyonsunuz! – Derek

2

Çok benzer bir proje üzerinde çalışıyorum.

Proje, büyük bir metin dosyasının yüklenmesini (en fazla yaklaşık 120 MB boyutunda ancak daha yükseğe gitmek istiyoruz) ve ardından bir ağaçtaki metin dosyasının bir taslağını oluşturmayı gerektirir. Ağaçtaki bir düğüme tıklamak, kullanıcıyı metin dosyasının o bölümüne kaydırır.

Çok sayıda insanla konuştuktan sonra, en iyi çözümün, kullanıcının bir keresinde rtb.Text dosyasına görebileceği kadar çok metin yüklediğiniz bir "sürgülü pencere" görüntüleyicisi oluşturmak olduğunu düşünüyorum.

Yani .. tüm dosyayı bir listeye yükleyiniz, ancak bu satırların 100'ünü rtb.Text dosyasına koyunuz. Kullanıcı yukarı kaydırırsa alt çizgiyi kaldırın ve üstüne bir metin satırı ekleyin. Aşağıya doğru kaydırırlarsa üst çizgiyi kaldırır ve bir metin satırı ekler. Bu çözümle oldukça iyi bir performans elde ediyorum. (120MB dosyasını yüklemek için 50s)

+0

Gerçekten büyük dosyaları destekleyen tüm düzenleyiciler, bir seferde sınırlı sayıda sayfa görüntüleyerek çalışır. Ayrıca, büyük miktarlarda metin işleyebilen kendi özel denetimlerini de kullanırlar. Verilerin sanallaştırılmasını * destekleyen * üçüncü taraf denetimleri vardır (yalnızca metnin görüntülenen kısmını yükleme ve işleme) –

0

Bunu benim için çalıştığımı deneyebilirsiniz.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Create new StreamReader 
    StreamReader sr = new StreamReader(openFileDialog1.FileName, Encoding.Default); 
    // Get all text from the file 
    string str = sr.ReadToEnd(); 
    // Close the StreamReader 
    sr.Close(); 

    // Show the text in the rich textbox rtbMain 
    backgroundWorker1.ReportProgress(1, str); 
} 

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    // richTextBox1.Text = e.ProgressPercentage.ToString() + " " + e.UserState.ToString(); 
    richTextBox1.Text = e.UserState.ToString(); 
} 
-1

Ben yükleme performansını iyileştirmek değilim ama uyumsuz benim richtextbox yüklemek için kullanabilirsiniz. Umarım bu size yardımcı olabilir.

XAML:

<RichTextBox Helpers:RichTextBoxHelper.BindableSource="{Binding PathFileName}" /> 

Yardımcısı:

public class RichTextBoxHelper 
{ 
private static readonly ILog m_Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

public static readonly DependencyProperty BindableSourceProperty = 
    DependencyProperty.RegisterAttached("BindableSource", typeof(string), typeof(RichTextBoxHelper), new UIPropertyMetadata(null, BindableSourcePropertyChanged)); 

public static string GetBindableSource(DependencyObject obj) 
{ 
    return (string)obj.GetValue(BindableSourceProperty); 
} 

public static void SetBindableSource(DependencyObject obj, string value) 
{ 
    obj.SetValue(BindableSourceProperty, value); 
} 

public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
{ 
    var thread = new Thread(
    () => 
    { 
     try 
     { 
     var rtfBox = o as RichTextBox; 
     var filename = e.NewValue as string; 
     if (rtfBox != null && !string.IsNullOrEmpty(filename)) 
     { 
      System.Windows.Application.Current.Dispatcher.Invoke(
      System.Windows.Threading.DispatcherPriority.Background, 
      (Action)delegate() 
      { 
       rtfBox.Selection.Load(new FileStream(filename, FileMode.Open), DataFormats.Rtf); 
      }); 
     } 
     } 
     catch (Exception exception) 
     { 
     m_Logger.Error("RichTextBoxHelper ERROR : " + exception.Message, exception); 
     } 
    }); 
    thread.Start(); 
} 
} 
2

WPF RichTextBox denetiminin kullanımı Akış Belge, RTB kontrolüne Akış Belgesi takmak sonra Zengin Metin görüntülemek ve Windows Form RichTextBox kumanda ekranı Zengin Metin ederken direkt olarak. WPF RTB'yi süper yavaş yapan . Eğer bir WinForm RTB kullanmakta sorun yoksa, sadece wpf uygulamasında barındırın. xaml:

<Window x:Class="WpfHostWfRTB.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"> 
<Grid> 
    <Grid> 
     <WindowsFormsHost Background="DarkGray" Grid.row="0" Grid.column="0"> 
      <wf:RichTextBox x:Name="rtb"/> 
     </WindowsFormsHost> 
    </Grid> 
</Grid> 
</Window> 

C# kodu

private void LoadTextDocument(string fileName, RichTextBox rtb) 
{ 
    System.IO.StreamReader objReader = new StreamReader(fileName); 
     if (File.Exists(fileName)) 
     { 
      rtb.AppendText(objReader.ReadToEnd()); 
     } 
     else rtb.AppendText("ERROR: File not found!"); 
     objReader.Close(); 
} 
+0

Arka plan iş parçacıkları ve diğer WPF RichTextBox korsanları için seçenekler tükettim: bir AppendText veya satır başına bir tane mi Hatta bir seçim ve içine Yüklü ham RTF ayarlamak, köpek yavaştı. Açıklayıcı yapılandırmanızı kullanarak, WPF'den winform'lara geçiyorum ve büyüklük hızından daha fazla bir hızda gördüm ve metni manipüle etmek ve indekslemek için kod da çok daha basit hale geldi. Çok teşekkürler! –