C#Out of Memory写入CSV

时间:2018-03-13 03:38:53

标签: c# csv out-of-memory

我一直在为我的一个朋友做一个小程序,他有一个非常大的文件,我读到了一个数据网格视图>修改数据>导出到csv。直到最近他让我对数据的导出方式做了一些改变,我设法使一切工作都相关。出于某种原因,我在运行此函数时遇到Out of Memory异常。

library(dplyr)

team.stats %>% 
  left_join(df.2017, by = c("team", "year")) %>% 
  left_join(df.2016, by = c("team", "year")) %>% 
  mutate(ppg = coalesce(ppg.x, ppg.y)) %>% 
  select(-ppg.x, -ppg.y)

#>     team year ppg
#> 1   Duke 2017  65
#> 2    UVA 2017  74
#> 3    UNC 2017  53
#> 4 Xavier 2017  63
#> 5   Duke 2016  68
#> 6    UVA 2016  61
#> 7    UNC 2016  82
#> 8 Xavier 2016  71

private void ExportData(int fileNum = 1, int rowCount = 0) { int lastRow = rowCount; if (!Directory.Exists(ExportPath + dataFilePath.Name)) Directory.CreateDirectory(ExportPath + dataFilePath.Name); StreamWriter sw = new StreamWriter(ExportPath + dataFilePath.Name + @"\" + dataFilePath.Name + "_" + fileNum + ".csv"); //var headers = dataGridView1.Columns.Cast<DataGridViewColumn>(); //sw.WriteLine(string.Join(",", headers.Select(column => "\"" + column.HeaderText + "\"").ToArray())); sw.WriteLine("Unit,UPC,Brand,Vendor,List Cost,QTY,Price,Description,Attribute 1,Attribute 2," + "Descriptor 1,Descriptor 2,Descriptor 3,Descriptor 4,Descriptor 5,Descriptor 6,Descriptor 7,Descriptor 8"); for (int i = 0; i < 50000; i++) { rowCount = lastRow + i; if (rowCount >= dataGridView1.RowCount) break; var cells = dataGridView1.Rows[rowCount].Cells.Cast<DataGridViewCell>(); sw.WriteLine(string.Join(",", cells.Select(cell => "\"" + cell.Value + "\"").ToArray())); } sw.Close(); sw.Dispose(); lastRow = rowCount + 1; if (lastRow < dataGridView1.RowCount - 1) ExportData(fileNum + 1, lastRow); else { progressBar1.BeginInvoke(new MethodInvoker(delegate { progressBar1.Style = ProgressBarStyle.Blocks; button_OpenDataFile.Enabled = true; button_ConvertFromRaw.Enabled = true; button_exportLS.Enabled = true; Console.WriteLine("[Main] Export complete."); })); } } 似乎是错误发生的那一行。

任何人都可以提供任何有关我做错的见解吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

执行此实验:将代码转换为循环,而不是使用递归:

private void ExportData()
{
    //You only need to do this once, take it out of the loop.
    if (!Directory.Exists(ExportPath + dataFilePath.Name))
        Directory.CreateDirectory(ExportPath + dataFilePath.Name);

    var fileNum = 0;
    var rowCount = 0;

    while (rowCount < dataGridView1.RowCount)
    {
        fileNum = fileNum + 1;

        using (StreamWriter sw = new StreamWriter(ExportPath + dataFilePath.Name + @"\" + dataFilePath.Name + "_" + fileNum + ".csv")
        {
            sw.WriteLine("Unit,UPC,Brand,Vendor,List Cost,QTY,Price,Description,Attribute 1,Attribute 2," +
                "Descriptor 1,Descriptor 2,Descriptor 3,Descriptor 4,Descriptor 5,Descriptor 6,Descriptor 7,Descriptor 8");

            for (int i = 0; i < 50000; i++)
            {
                rowCount = rowCount + 1;

                if (rowCount >= dataGridView1.RowCount)
                    break;
                var cells = dataGridView1.Rows[rowCount].Cells.Cast<DataGridViewCell>();
                sw.WriteLine(string.Join(",", cells.Select(cell => "\"" + cell.Value + "\"").ToArray()));
            }
        }   //sw.Close() and sw.Dispose() not needed because of the 'using'. You may want to do sw.Flush().
    }

    //The 'else' part of your original recursive method
    progressBar1.BeginInvoke(new MethodInvoker(delegate {
        progressBar1.Style = ProgressBarStyle.Blocks;
        button_OpenDataFile.Enabled = true;
        button_ConvertFromRaw.Enabled = true;
        button_exportLS.Enabled = true;

        Console.WriteLine("[Main] Export complete.");
    }));
}

错误会消失吗?可能是。递归在堆栈中使用大量内存,并且在递归结束时再次向上移动时不会释放它。您收到错误的行恰好尝试将csv文件中整行的内容添加到内存中。如果内存已经几乎已经满了递归堆栈,那么这可能是导致内存不足异常的最后一次丢弃。

我删除了一些似乎多余的累加器变量,我希望我没有弄乱循环的范围。

我从循环中删除了CreateDirectory,并为using添加了StreamWriter语句。我不认为这些是你的错误的原因,因为目录只创建了一次,而你在递归调用之前处理了StreamWriter,但无论如何如果要确认它,你可以尝试撤消这些更改在非递归代码中逐个查看,并查看错误是否再次发生。

答案 1 :(得分:0)

所以我明白了。
我想迭代通过datagridview只是不是要走的路。
相反,我只是使用我的数据源导出数据。它的速度要快得多......从2分钟到2秒左右。

谢谢大家的帮助!

private void ExportData()
    {
        //You only need to do this once, take it out of the loop.
        if (!Directory.Exists(ExportPath + dataFilePath.Name))
            Directory.CreateDirectory(ExportPath + dataFilePath.Name);

        var fileNum = 0;
        var rowCount = 0;

        while (rowCount < dataGridView1.RowCount)
        {
            fileNum = fileNum + 1;

            using (StreamWriter sw = new StreamWriter(ExportPath + dataFilePath.Name + @"\" + dataFilePath.Name + "_" + fileNum + ".csv"))
            {
                sw.WriteLine("Unit,UPC,Brand,Vendor,List Cost,QTY,Price,Description,Attribute 1,Attribute 2" +
                "Descriptor 1,Descriptor 2,Descriptor 3,Descriptor 4,Descriptor 5,Descriptor 6,Descriptor 7,Descriptor 8");

                for (int i = 0; i < 50000; i++)
                {
                    rowCount = rowCount + 1;

                    if (rowCount >= dataGridView1.RowCount)
                        break;
                    var s = new string[]
                    {
                        "\"" + DATA[rowCount].Unit + "\"",
                        "\"" + DATA[rowCount].UPC + "\"",
                        "\"" + DATA[rowCount].Brand + "\"",
                        "\"" + DATA[rowCount].Vendor + "\"",
                        "\"" + DATA[rowCount].List_Cost + "\"",
                        "\"" + DATA[rowCount].Quantity.ToString() + "\"",
                        "\"" + DATA[rowCount].Price + "\"",
                        "\"" + DATA[rowCount].Description + "\"",
                        "\"" + DATA[rowCount].Attribute_1 + "\"",
                        "\"" + DATA[rowCount].Attribute_2 + "\"",
                        "\"" + DATA[rowCount].Descriptor_1 + "\"",
                        "\"" + DATA[rowCount].Descriptor_2 + "\"",
                        "\"" + DATA[rowCount].Descriptor_3 + "\"",
                        "\"" + DATA[rowCount].Descriptor_4 + "\"",
                        "\"" + DATA[rowCount].Descriptor_5 + "\"",
                        "\"" + DATA[rowCount].Descriptor_6 + "\"",
                        "\"" + DATA[rowCount].Descriptor_7 + "\"",
                        "\"" + DATA[rowCount].Descriptor_8 + "\""
                    };
                    sw.WriteLine(string.Join(",", s));
                    sw.Flush();
                }
            }   //sw.Close() and sw.Dispose() not needed because of the 'using'. You may want to do sw.Flush().
        }

        //The 'else' part of your original recursive method
        progressBar1.BeginInvoke(new MethodInvoker(delegate
        {
            progressBar1.Style = ProgressBarStyle.Blocks;
            button_OpenDataFile.Enabled = true;
            button_ConvertFromRaw.Enabled = true;
            button_exportLS.Enabled = true;

            Console.WriteLine("[Main] Export complete.");
        }));
    }'