2012-11-15 45 views
3

我使用這個代碼導入文本文件到我的列表框C#ListBox中導入從文本文件崩潰

 OpenFileDialog openFileDialog1 = new OpenFileDialog(); 
     openFileDialog1.Filter = "Text Files|*.txt"; 
     openFileDialog1.Title = "Select a Text file"; 
     openFileDialog1.FileName = ""; 
     DialogResult result = openFileDialog1.ShowDialog(); 
     if (result == DialogResult.OK) 
     { 
      string file = openFileDialog1.FileName; 

      string[] text = System.IO.File.ReadAllLines(file); 
      foreach (string line in text) 
      { 
       listBox2.Items.Add(line); 

      } 
      listBox2.Items.Add(""); 
     } 

它工作正常的小文本文件,用10行左右,但是當我嘗試導入更大列表,(4-5兆字節)該程序沒有響應,並且正在崩潰。

任何幫助?

+0

4-5兆字節文件中有多少行? – 3aw5TZetdf

+1

崩潰時的錯誤是什麼? –

+0

我可能是錯的,但如果我沒記錯的話,列表框上有64k的限制 – DarkSquirrel42

回答

0

可以使用流來存儲數據:

class Test 
{ 

public static void Main() 
{ 
    string path = @"c:\temp\MyTest.txt"; 

    //Create the file. 
    using (FileStream fs = File.Create(path)) 
    { 
     AddText(fs, "This is some text"); 
     AddText(fs, "This is some more text,"); 
     AddText(fs, "\r\nand this is on a new line"); 
     AddText(fs, "\r\n\r\nThe following is a subset of characters:\r\n"); 

     for (int i=1;i < 120;i++) 
     { 
      AddText(fs, Convert.ToChar(i).ToString()); 

     } 
    } 

    //Open the stream and read it back. 
    using (FileStream fs = File.OpenRead(path)) 
    { 
     byte[] b = new byte[1024]; 
     UTF8Encoding temp = new UTF8Encoding(true); 
     while (fs.Read(b,0,b.Length) > 0) 
     { 
      Console.WriteLine(temp.GetString(b)); 
     } 
    } 
} 

private static void AddText(FileStream fs, string value) 
{ 
    byte[] info = new UTF8Encoding(true).GetBytes(value); 
    fs.Write(info, 0, info.Length); 
} 

}

,那麼你的事件處理程序

privateasyncvoid Button_Click(object sender, RoutedEventArgs e) 
    { 
     UnicodeEncoding uniencoding = new UnicodeEncoding(); 
     string filename = @"c:\Users\exampleuser\Documents\userinputlog.txt"; 

     byte[] result = uniencoding.GetBytes(UserInput.Text); 

     using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate)) 
     { 
      SourceStream.Seek(0, SeekOrigin.End); 
      await SourceStream.WriteAsync(result, 0, result.Length); 
     } 
    } 
+0

該文件有541207行,我該怎麼辦:)? – user1815324

+1

您是否必須將它們全部顯示給用戶?一次? –

+0

這並不重要。他們只需要導入列表。沒有必要看到它。 – user1815324

0

它也許根本就沒有完成其工作,你應該必須等待更多。嘗試使用此解決方案:

http://www.bytechaser.com/en/articles/f3a3niqyb7/display-large-lists-in-listview-control-quickly.aspx

+0

我寧願使用listBox而不是listView。 – user1815324

+0

如果用戶不需要看到它,請不要使用用戶控件。在內存中使用某些內容,例如流或將其存儲在字符串中。 –

+0

是的,你將不得不放棄用戶控件,如litBox和listView,並使用流 –

1

通過使用這樣的:

string[] text = System.IO.File.ReadAllLines(file); 
listBox1.Items.AddRange(text); 

,而不是這樣的:

string[] text = System.IO.File.ReadAllLines(file); 
foreach (string line in text) 
{ 
     listBox2.Items.Add(line); 
} 

你將加快執行速度,因爲你至少10-15倍不會使每個商品插入的listBox失效。我用幾千行測量過。

如果文本的行數太多,瓶頸也可能是ReadAllLines。即使我不知道爲什麼你會插入這麼多的線,用戶是否能夠找到他/她需要的線?

編輯 OK那麼我建議你使用BackgroundWorker的,這裏是代碼:

首先你初始化的BackgroundWorker:

BackgroundWorker bgw; 
     public Form1() 
     { 
      InitializeComponent(); 
      bgw = new BackgroundWorker(); 
      bgw.DoWork += new DoWorkEventHandler(bgw_DoWork); 
      bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted); 
     } 

然後你把它在你的方法:

private void button1_Click(object sender, EventArgs e) 
     { 
      if (!bgw.IsBusy) 
      { 
       OpenFileDialog openFileDialog1 = new OpenFileDialog(); 
       openFileDialog1.Filter = "Text Files|*.txt"; 
       openFileDialog1.Title = "Select a Text file"; 
       openFileDialog1.FileName = ""; 
       DialogResult result = openFileDialog1.ShowDialog(); 
       if (result == DialogResult.OK) 
       { 
        string file = openFileDialog1.FileName; 
        listView1.BeginUpdate(); 
        bgw.RunWorkerAsync(file); 
       } 
      } 
      else 
       MessageBox.Show("File reading at the moment, try later!"); 
     } 


     void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      listView1.EndUpdate(); 
     } 
     void bgw_DoWork(object sender, DoWorkEventArgs e) 
     { 
      string fileName = (string)e.Argument; 
      TextReader t = new StreamReader(fileName); 
      string line = string.Empty; 
      while ((line = t.ReadLine()) != null) 
      { 
       string nLine = line; 
       this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(nLine); }); 
      } 
     } 

這將增加每個行,當它讀取它,你將有響應性的UI,並且線條不會影響列表框中它finishe前s loading。

+0

同樣,我不知道:( – user1815324

+0

現在檢查答案! –

+0

你檢查了答案嗎? –

0

您的應用程序變得無響應,因爲它正在等待ReadAllLines方法來完成並阻止UI線程。您可能需要在單獨的線程上讀取文件以避免阻止用戶界面。我不能保證下面的代碼無誤地工作,但它應該給你一個關於如何解決問題的想法。

首先,你需要一個方法將項目追加到ListBox:如果是在UI線程,如果是執行

private void AddListBoxItem(string item) 
{ 
    if(!InvokeRequired) 
    { 
     listBox2.Items.Add(item); 
    } 
    else 
    { 
     var callback = new Action<string>(AddListBoxItem); 
     Invoke(callback, new object[]{item}); 
    } 
} 

上面的檢查方法,它只是增加了一個項目listBox2.Items集合;如果不是,它會自己創建一個委託並在UI線程上調用該委託。

接下來,您需要將讀取文件的代碼移動到另一個線程,並調用AddListBoxItem方法。對於可讀性的原因,讓我們將它放入一個單獨的方法:

private void AddFileContentsToList(string fileName) 
{ 
    using(var reader = new System.IO.StreamReader(fileName)) 
    { 
     while(!reader.EndOfStream) 
     { 
      var line = reader.ReadLine(); 
      AddListBoxItem(line); 
     } 
    } 
} 

現在,我們將調用該方法在一個單獨的線程:

OpenFileDialog openFileDialog1 = new OpenFileDialog(); 
openFileDialog1.Filter = "Text Files|*.txt"; 
openFileDialog1.Title = "Select a Text file"; 
openFileDialog1.FileName = ""; 
DialogResult result = openFileDialog1.ShowDialog(); 
if (result == DialogResult.OK) 
{ 
    var thread = new Thread(AddFileContentsToList); 
    thread.Start(); 
} 

希望這有助於!