2009-05-07 2 views
6

Мне нужно загрузить текстовый файл диапазона размером 10 МБ в WPF RichTextBox, но мой текущий код замораживает пользовательский интерфейс. Я попробовал сделать фоновый рабочий, выполнив загрузку, но это тоже не слишком хорошо работает.C# - Загрузка большого файла в WPF RichTextBox?

Вот мой код загрузки. Есть ли способ улучшить его работу? Благодарю.

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

ответ

1

Почему вы не добавить в строковую переменную (или, возможно, даже использовать StringBuilder), а затем присвоить значение свойству .text, когда вы закончите разбор?

+0

вы говорите о первом блоке кода или второй? – 2009-05-07 21:19:20

-1

Считаете ли вы попыткой сделать приложение многопоточным?

Какой объем текстового файла вам нужно увидеть сразу? Вы можете захотеть взглянуть на ленивую загрузку в .NET или в вашем случае C#

3

Графические элементы управления просто не предназначены для обработки данных такого рода, просто потому, что они станут неработоспособными. Даже если управление может обрабатывать большую строку, то, что видно в элементе управления, настолько мало по сравнению со всем текстом, что полосы прокрутки станут практически бесполезными. Чтобы найти определенную строку в тексте, вам нужно будет переместить ползунок в ближайшую позицию, которую он мог бы указать, затем прокручивать строку за раз в минутах ...

Вместо того, чтобы отправлять пользователям что-то бесполезное , вы должны переосмыслить, как вы отображаете данные, чтобы вы могли сделать это таким образом, который действительно можно было бы использовать.

+3

Это не необоснованная вещь. Я могу открывать файлы с несколькими ГБ в UltraEdit без проблем. Это не RTF, конечно, но многие коммерческие IDE обрабатывают файлы в диапазоне 10 МБ достаточно хорошо - и имейте в виду, что они должны анализировать синтаксис языка, чтобы получить красивые цвета, а не просто читать предварительно обработанное форматирование. –

+1

@ Richard: Да, есть программы, которые могут обрабатывать большие файлы, но нет простого элемента управления GUI. Редактирование такой большой строки означает, что вы копируете 20 ГБ данных для каждого небольшого изменения, поэтому элемент управления будет очень вялым. Программы, обрабатывающие большие файлы, используют другой способ представления данных в памяти. – Guffa

+0

@downvoter: Почему downvote? Если вы не объясните, что это такое, что вы считаете неправильным, оно не может улучшить ответ. – Guffa

1

Я обратил внимание на использование RichTextboxes, поскольку по мере добавления дополнительных строк они начинают замедляться. Если вы можете сделать это, не добавляя «\ n», это ускорится для вас. Помните, что каждый '\ n' является новым блоком объектов абзаца для RichTextbox.

Это мой метод загрузки файла размером 10 МБ. Загрузка занимает около 30 секунд. Я использую диалоговое окно индикатора выполнения, чтобы мой пользователь знал, что на загрузку потребуется время.

// 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

Это '\ n ', а не'/n '. – markwatson

+0

Вы, сэр, чемпион! – Derek

2

Я работаю над очень похожим проектом.

Проект предполагает загрузку большого текстового файла (максимальный размер приблизительно: 120 МБ, но мы хотим идти выше), а затем конструируем контур текстового файла в дереве. Щелчок по узлу в дереве прокручивает пользователя к этой части текстового файла.

После разговора с большим количеством людей я считаю, что лучшим решением является создание своего рода «скользящего окна», в котором вы загружаете столько текста, сколько пользователь может видеть за раз в rtb.Text.

Итак, скажем, загрузите весь файл в список, но поместите только 100 этих строк в rtb.Text. Если пользователь прокручивает вверх, удалите нижнюю строку и добавьте строку текста вверху. Если они прокручиваются вниз, удалите верхнюю строку и добавьте строку текста внизу. Я получаю довольно хорошую производительность с этим решением. (50 секунд для загрузки файла размером 120 МБ)

+0

Все редакторы, которые поддерживают действительно большие файлы, работают, показывая ограниченное количество страниц за раз. Они также используют собственные настраиваемые элементы управления, которые могут обрабатывать большие объемы текста. Есть сторонние элементы управления, которые * делают * поддержку виртуализации данных (загрузка и отображение только отображаемой части текста) –

0

Вы можете попробовать, это сработало для меня.

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

Я не улучшаю производительность загрузки, но я использую его для загрузки моего richtextbox асинхронно. Надеюсь, это поможет вам.

XAML:

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

Helper:

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 Документооборот для отображения Rich Text, а затем присоединить поток документов для управления RTB, а дисплей управления Windows Form RichTextBox Rich Text непосредственно. вот что делает WPF RTB очень медленным. , если вы согласны с использованием WinForm RTB, просто разместите его в своем приложении wpf. Часть 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# код

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

Я исчерпал опции для фоновых потоков и других хакеров WPF RichTextBox: был ли у меня один AppendText или один на строку, или даже установил выбор и загрузил необработанный RTF в него, это была собака медленная. Используя вашу иллюстративную конфигурацию, я переключаюсь с WPF на winforms и видел более чем на порядок превышение скорости, а код для манипулирования и индексации текста также стал более простым. Большое спасибо! –

Смежные вопросы