1

私は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

高速読み取りとグリッドでの表示のために、このコードを最適化するためのアドバイスが必要です。

4

4 に答える 4

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());
于 2013-01-04T12:30:41.387 に答える
2

データをグリッドに直接配置する代わりに、 の を確認する必要がありVirtualModeますDataGridView

コードでは、一度に 2 つのこと (ファイルの読み取り、グリッドの塗りつぶし) を行っているため、GUI がフリーズします。代わりに、グリッドを仮想モードにしBackgroundWorkerて、グリッドのデータを保持するリストにファイルを読み込む必要があります。バックグラウンド ワーカーは、各行の読み取り後にグリッドの仮想サイズを更新できます。これにより、グリッドの読み込み中にデータを既に確認できます。このアプローチを使用すると、スムーズに機能するグリッドが得られます。

以下に、 aと aDataGridViewの 2 つのテキスト列を持つを使用するフォームに入力する必要がある例を示します。BackgroundWorkerButton

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; }
    }
}
于 2013-01-04T12:36:14.037 に答える
2

速度に関して最適化することはあまりありませんが、以下ははるかに読みやすくなっています。遅すぎる場合は、おそらくファイルを読み取るメソッドではなく、 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);
            }
        }
    }
于 2013-01-04T12:52:32.727 に答える
2

SuspendLayout()およびResumeLayout()メソッドの使用を試すことができます。

MSDN ドキュメントから 「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();
于 2013-01-04T12:55:26.497 に答える