大文件CSV转置在C#中永远需要

时间:2014-11-19 23:20:30

标签: c# python csv transpose

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

最初,我使用内置的zip函数实现了这个Python。我处理源文件以从short中分隔长行,然后用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函数以给出总行数和行数,因此我可以知道outfile必须有多大。

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

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

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

1 个答案:

答案 0 :(得分:3)

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

  • 创建List<string>行,然后进行一次调用System.IO.File.WriteAllLines(filename, lines)。这将减少磁盘IO。

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

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

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