在C#中优化大型文件的Listview

时间:2013-12-05 00:47:21

标签: c# listview io streamreader streamwriter

我有一个C#程序正在提取一个大约的.csv文件。 42,000行长。文件中的所有数据都存储如下:

Zipcode,City,State

我将所有信息都放在listview中的三个不同列中。

目前这个数据大约需要30到50秒才能进入我的程序。我的问题是如何才能更好地优化我的代码以缩短时间?

以下是我的代码片段。评论的代码是我之前尝试过的代码,但没有成功减少时间,因此我以一种更容易阅读的方式重写了它。

 //These are globally declared.
lvZip.Columns.Add("Zipcode", 150, HorizontalAlignment.Left);
lvZip.Columns.Add("City", 150, HorizontalAlignment.Left);
lvZip.Columns.Add("State", 150, HorizontalAlignment.Left);
lvZip.View = View.Details;

lvZip.Items.Clear();

        //string dir = System.IO.Path.GetDirectoryName(
        //  System.Reflection.Assembly.GetExecutingAssembly().Location);

        //string path = dir + @"\zip_code_database_edited.csv";
        //var open = new StreamReader(File.OpenRead(path));

        //foreach (String s in File.ReadAllLines(path))
        //{
        //    Zipinfo = s.Split(',');
        //    Zipinfo[0] = Zipinfo[0].Trim();
        //    Zipinfo[1] = Zipinfo[1].Trim();
        //    Zipinfo[2] = Zipinfo[2].Trim();
        //    lvItem = new ListViewItem(Zipinfo);
        //    lvZip.Items.Add(lvItem);
        //}
        //open.Close();

        StreamReader myreader = File.OpenText(path);
        aLine = myreader.ReadLine();

        while (aLine != null)
        {
            Zipinfo = aLine.Split(',');
            Zipinfo[0] = Zipinfo[0].Trim();
            Zipinfo[1] = Zipinfo[1].Trim();
            Zipinfo[2] = Zipinfo[2].Trim();
            lvItem = new ListViewItem(Zipinfo);
            lvZip.Items.Add(lvItem);
            aLine = myreader.ReadLine();
        }
        myreader.Close();

4 个答案:

答案 0 :(得分:5)

您应该做的是在向ListView添加任何内容之前和之后使用ListView.BeginUpdate()ListView.EndUpdate()。第二件事是使用ListView.AddRange()而不是ListView.Add()。通过使用Add方法,每次使用时都会重绘ListView。但是,使用ListView.AddRange(),您只会重绘一次。这应该为你做一点优化。

答案 1 :(得分:2)

您可以尝试:

lvZip.BeginUpdate();

开始添加所有项目之前。

然后:

lvZip.EndUpdate();

当你完成。

这会阻止控件在添加时绘制每个项目,这会使整个过程非常缓慢。

答案 2 :(得分:2)

黄金法则:不要使用String.Split()来读取CSV数据。

.NET Framework已经有一个名为TextFieldParser的内置专用CSV解析器。

它位于Microsoft.VisualBasic.FileIO名称空间。

String.Split()不仅没有正确处理的边缘情况,而且使用StreamReader的速度也慢得多。

最后一句话:提示是使用using语句以确保您的一次性对象被释放(释放非托管资源)。我在上面的代码中看到你没有使用它们(双关语)。

实际上,这远远超出了本问题的范围,因为有效的内存管理可以提高代码的性能。

答案 3 :(得分:0)

可能还有一点工作,但使用带有用作数据源的文本文件的DataGridView,您可以在42,000行.csv的2秒内获得加载时间。以下是一些代码:

    private void button2_Click(object sender, EventArgs e)
    {
        string errorInfo = String.Empty;
        //open text file into Dataset:
        string textFilePath = @"textfile1.csv";

        DataSet dataTextFile = new DataSet("textfile");
        if(!LoadTextFile(textFilePath, dataTextFile, out errorInfo))
        {
            MessageBox.Show("Failed to load text file:\n" + errorInfo,
                "Load Text File");
            return;
        }
        dgTextFile.DataSource = dataTextFile.Tables[0];
        dataTextFile.Dispose(); 
    }

    private bool LoadTextFile(string textFilePath, DataSet dataToLoad, out string errorInfo)
    {
        errorInfo = String.Empty;

        try
        {
            string textFileFolder = (new System.IO.FileInfo(textFilePath)).DirectoryName;
            string textConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;" +
                                            "Data Source=" + textFileFolder + ";" +
                                            "Extended Properties=\"text;\";";
            OleDbConnection textConnection = new OleDbConnection(textConnectionString);

            textConnection.Open();

            textFilePath = (new System.IO.FileInfo(textFilePath)).Name;
            string selectCommand = "select * from " + textFilePath;

            //open command:
            OleDbCommand textOpenCommand = new OleDbCommand(selectCommand);
            textOpenCommand.Connection = textConnection;

            OleDbDataAdapter textDataAdapter = new OleDbDataAdapter(textOpenCommand);

            int rows = textDataAdapter.Fill(dataToLoad);

            textConnection.Close();
            textConnection.Dispose();

            return true;
        }
        catch(Exception ex_load_text_file)
        {
            errorInfo = ex_load_text_file.Message;
            return false;
        }
    }

部分代码来自MSDN示例,但我似乎无法找到该页面。