我在Windows Forms .NET 3.5中有以下内容
对于记录小于10,000的csv,它可以正常工作,但对于30,000以上的记录则较慢。 输入csv文件可以在1 - 1,00,000条记录之间任意记录
目前使用的代码:
/// <summary>
/// This will import file to the collection object
/// </summary>
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
需要一些关于优化此代码以获得快速读取和建议的建议。在网格中查看。
答案 0 :(得分:7)
List<string[]> 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;
试试看,我怀疑你在数据网格中有某种形式的列名,现在我只是将它们设为1和2。
要根据原始代码进行过滤,请使用:
List<string[]> rows = File.ReadAllines("Path").Select(x => x.Split(',')).Where(x => x[0] != "" && x[1] != "").ToList();
从DataGridView
dt.Columns.AddRange(dgv.Columns.Cast<DataGridViewColumn>().Select(x => new DataColumn(x.Name)).ToArray());
答案 1 :(得分:2)
您应该查看VirtualMode
of the DataGridView
。
在你的代码中,你一次做两件事(阅读文件,填充网格),这会导致你的冻结gui。相反,您应该将网格置于虚拟模式,并将BackgroundWorker
内的文件读入保存网格数据的列表中。后台工作者可以在每行读取后更新网格的虚拟大小,这允许在网格加载时已经看到数据。通过使用这种方法,您将获得平稳的工作网格。
您将在下面找到一个示例,只需填写一个表单,该表单使用DataGridView
,其中包含两个文本列,BackgroundWorker
和Button
:
public partial class FormDemo : Form
{
private List<Element> _Elements;
public FormDemo()
{
InitializeComponent();
_Elements = new List<Element>();
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; }
}
}
答案 2 :(得分:2)
在速度方面没有太多优化,但追随更具可读性。如果它太慢,可能不是读取文件的方法,而是需要显示&gt; 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);
}
}
}
答案 3 :(得分:2)
您可以尝试使用SuspendLayout()和ResumeLayout()方法。
From MSDN Documentation “在调整控件的多个属性时,SuspendLayout和ResumeLayout方法串联使用以抑制多个Layout事件。例如,您通常会调用SuspendLayout方法,然后设置控件的Size,Location,Anchor或Dock属性,然后调用ResumeLayout方法以使更改生效。“
accountsDataGridView.SuspendLayout();
accountsDataGridView.Rows.Clear();
// .....
// in the end after you finished populating your grid call
accountsDataGridView.ResumeLayout();