我正在尝试转置一个可能有许多行和列的大型数据文件,以便在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
来存储每行的行长度,这样我就可以避免异常。 这会解决这个问题吗?
-
尝试使用
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];
}