大文件 CSV 转置在 C# 中需要很长时间

本文关键字:长时间 文件 CSV 转置 | 更新日期: 2023-09-27 18:31:00

我正在尝试转置一个可能有许多行和列的大型数据文件,以便在Excel中进行后续分析。 目前行可能包含 2 或 125,000 个点,但我正在尝试通用。 (我需要转置,因为 Excel 无法处理那么多列,但如果大型集跨越许多行,那就没问题了。

最初,我使用内置的zip函数实现了这是Python。 我处理源文件以将长行与短行分开,然后使用 zip 转置长行:

tempdata = zip(*csv.reader(open(tempdatafile,'r')))
csv.writer(open(outfile, 'a', newline='')).writerows(tempdata)
os.remove(tempdatafile)

这很好用,对于 15MB csv 文件需要几秒钟,但由于首先生成数据的程序是 C#,我认为最好在一个程序中完成所有操作。

我在 C# 中的初始方法略有不同,因为从我所读到的内容来看,zip 函数的工作方式可能并不完全相同。 这是我的方法:

public partial class Form1 : Form
{
    StreamReader source;
    int Rows = 0;
    int Columns = 0;
    string filePath = "input.csv";
    string outpath = "output.csv";
    List<string[]> test_csv = new List<string[]>();
    public Form1()
    {
        InitializeComponent();
    }
    private void button_Load_Click(object sender, EventArgs e)
    {
        source = new StreamReader(filePath);
        while(!source.EndOfStream)
        {
            string[] Line = source.ReadLine().Split(',');
            test_csv.Add(Line);
            if (test_csv[Rows].Length > Columns) Columns = test_csv[Rows].Length;
            Rows++;
        }
    }
    private void button_Write_Click(object sender, EventArgs e)
    {
        StreamWriter outfile = new StreamWriter(outpath);
        for (int i = 0; i < Columns; i++)
        {
            string line = "";
            for (int j = 0; j < Rows; j++)
            {
                try
                {
                    if (j != 0) line += ",";
                    line += test_csv[j][i];
                }
                catch { }
            }
            outfile.WriteLine(line);
        }
        outfile.Close();
        MessageBox.Show("Outfile written");
    }
}

我使用了List,因为行的长度可能是可变的,并且我设置了 load 函数来为我提供列和行的总数,以便我可以知道输出文件必须有多大。

我在编写时使用了try/catch来处理可变长度的行。 如果索引超出行的范围,这将捕获异常并跳过它(下一个循环在异常发生之前写入逗号)。

加载只需要很少的时间,但实际上保存输出文件是一个极其漫长的过程。2 小时后,我只完成了文件的 1/3。 不过,当我停止程序并查看输出文件时,一切都正确完成。

是什么原因导致此程序花费这么长时间? 这都是异常处理吗? 我可以实现第二个List来存储每行的行长度,这样我就可以避免异常。 这会解决这个问题吗?

大文件 CSV 转置在 C# 中需要很长时间

  • 尝试使用 StringBuilder 。 长字符串的串联(+)效率非常低。

  • 创建线路List<string>,然后进行单个呼叫System.IO.File.WriteAllLines(filename, lines)。 这将减少磁盘 IO。

  • 如果您不关心点的顺序,请尝试将外部 for 循环更改为 System.Threading.Tasks.Parallel.For 。 这将运行多个线程。 由于它们并行运行,因此在写出时不会保留顺序。

关于您的异常处理:由于这是您可以提前确定的错误,因此不应使用try/catch来处理它。 将其更改为:

if (j < test_csv.Length && i < test_csv[j].Length)
{
  line += test_csv[j][i];
}