更快捷地将csv读取到网格

我在Windows Forms .NET 3.5中有以下内容

它适用于记录小于10,000的csv,但对于30,000以上的记录则较慢。 输入csv文件可以在1 – 1,00,000条记录之间进行任何记录

目前使用的代码:

///  /// This will import file to the collection object ///  private bool ImportFile() { try { String fName; String textLine = string.Empty; String[] splitLine; // clear the grid view accountsDataGridView.Rows.Clear(); fName = openFileDialog1.FileName; if (System.IO.File.Exists(fName)) { System.IO.StreamReader objReader = new System.IO.StreamReader(fName); do { textLine = objReader.ReadLine(); if (textLine != "") { splitLine = textLine.Split(','); if (splitLine[0] != "" || splitLine[1] != "") { accountsDataGridView.Rows.Add(splitLine); } } } while (objReader.Peek() != -1); } return true; } catch (Exception ex) { if (ex.Message.Contains("The process cannot access the file")) { MessageBox.Show("The file you are importing is open.", "Import Account", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { MessageBox.Show(ex.Message); } return false; } } 

示例输入文件:
18906,Y
18908,Y
18909,Y
18910,Y
18912,N
18913,N

需要一些关于优化此代码的建议,以便快速读取和查看网格。

 List rows = File.ReadAllLines("Path").Select(x => x.Split(',')).ToList(); DataTable dt = new DataTable(); dt.Columns.Add("1"); dt.Columns.Add("2"); rows.ForEach(x => { dt.Rows.Add(x); }); dgv.DataSource = dt; 

试试看,我怀疑你在数据网格中有某种forms的列名,现在我只做了1和2。

要根据原始代码进行过滤,请使用:

 List rows = File.ReadAllines("Path").Select(x => x.Split(',')).Where(x => x[0] != "" && x[1] != "").ToList(); 

DataGridView获取列

  dt.Columns.AddRange(dgv.Columns.Cast().Select(x => new DataColumn(x.Name)).ToArray()); 

在速度方面没有太多优化,但是后续更易读。 如果它太慢,它可能不是读取文件的方法,而是需要显示> 30k记录的WinForm。

  accountsDataGridView.Rows.Clear(); using (FileStream file = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096)) using (StreamReader reader = new StreamReader(file)) { while (!reader.EndOfStream) { var fields = reader.ReadLine().Split(','); if (fields.Length == 2 && (fields[0] != "" || fields[1] != "")) { accountsDataGridView.Rows.Add(fields); } } } 

您可以尝试使用SuspendLayout()和ResumeLayout()方法。

从MSDN文档 “在调整控件的多个属性时,SuspendLayout和ResumeLayout方法串联使用以抑制多个布局事件。例如,您通常会调用SuspendLayout方法,然后设置Size,Location,Anchor或Dock属性控件,然后调用ResumeLayout方法以使更改生效。“

 accountsDataGridView.SuspendLayout(); accountsDataGridView.Rows.Clear(); // ..... // in the end after you finished populating your grid call accountsDataGridView.ResumeLayout(); 

您应该查看DataGridViewVirtualMode ,而不是将数据直接放入网格中。

在你的代码中,你一次做两件事(阅读文件,填充网格),这会导致你的冻结gui。 相反,您应该将网格置于虚拟模式,并将BackgroundWorker的文件读入保存网格数据的列表中。 后台工作者可以在每行读取后更新网格的虚拟大小,这允许在网格加载时已经看到数据。 通过使用这种方法,您将获得平稳的工作网格。

下面你将找到一个例子,它只需要填充到一个表格中,该表格使用带有两个文本列的DataGridView ,一个BackgroundWorker和一个Button

 public partial class FormDemo : Form { private List _Elements; public FormDemo() { InitializeComponent(); _Elements = new List(); dataGridView.AllowUserToAddRows = false; dataGridView.AllowUserToDeleteRows = false; dataGridView.ReadOnly = true; dataGridView.VirtualMode = true; dataGridView.CellValueNeeded += OnDataGridViewCellValueNeeded; backgroundWorker.WorkerReportsProgress = true; backgroundWorker.DoWork += OnBackgroundWorkerDoWork; backgroundWorker.ProgressChanged += OnBackgroundWorkerProgressChanged; backgroundWorker.RunWorkerCompleted += OnBackgroundWorkerRunWorkerCompleted; } private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e) { var filename = (string)e.Argument; using (var reader = new StreamReader(filename)) { string line = null; while ((line = reader.ReadLine()) != null) { var parts = line.Split(','); if (parts.Length >= 2) { var element = new Element() { Number = parts[0], Available = parts[1] }; _Elements.Add(element); } if (_Elements.Count % 100 == 0) { backgroundWorker.ReportProgress(0); } } } } private void OnBackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e) { dataGridView.RowCount = _Elements.Count; } private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { dataGridView.RowCount = _Elements.Count; button.Enabled = true; } private void OnButtonLoadClick(object sender, System.EventArgs e) { if (!backgroundWorker.IsBusy && DialogResult.OK == openFileDialog.ShowDialog()) { button.Enabled = false; backgroundWorker.RunWorkerAsync(openFileDialog.FileName); } } private void OnDataGridViewCellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { var element = _Elements[e.RowIndex]; switch (e.ColumnIndex) { case 0: e.Value = element.Number; break; case 1: e.Value = element.Available; break; } } private class Element { public string Available { get; set; } public string Number { get; set; } } }