将 .csv 文件解析成二维数组

12

我正在尝试将一个CSV文件解析成C#中的二维数组。我遇到了一个非常奇怪的问题,以下是我的代码:

string filePath = @"C:\Users\Matt\Desktop\Eve Spread Sheet\Auto-Manufacture.csv";
StreamReader sr = new StreamReader(filePath);
data = null; 
int Row = 0;
while (!sr.EndOfStream)
{
    string[] Line = sr.ReadLine().Split(',');
    if (Row == 0)
    {
        data = new string[Line.Length, Line.Length];
    }
    for (int column = 0; column < Line.Length; column++)
    {
        data[Row, column] = Line[column];
    }
    Row++;
    Console.WriteLine(Row);
}

我的 .csv 文件有 87 行,但在执行时出现了一个奇怪的问题,它会按预期将前 15 行读入数据数组,但当到达第 16 次 data[Row, column] = Line[column]; 行时,它似乎就会跳出整个循环(没有满足 sr.EndOfStream 的条件),并且不再读取任何数据到数据数组中。

有人能解释一下可能发生了什么吗?


2
每行的列数都相同吗?列数是否等于行数?您正在将数组中的总行数初始化为 CSV 第一行中的列数。 - matthewrdev
我觉得你的CSV文件里可能有一些特殊字符。先删除CSV文件的前15行,然后上传它。如果还是出现同样的错误,请回复。 - sourabh devpura
我删除了第16行,同样的事情发生了,我删除了15行左右的几行代码,同样的事情发生了。看起来它只能读取15行,但没有解释为什么,实际上代码从未离开while循环,并且之后不执行任何操作。这是我在编程中遇到的最奇怪的事情。 - user1296932
@MattR,有87行,但并非所有行都具有相同数量的列。但是对于前15行,它只是用空值填充空白处,正如预期的那样,因此我认为这不是问题所在。 - user1296932
你的代码中的 line.length 是什么意思?因为你是通过它来指定数组大小的。 - sourabh devpura
显示剩余3条评论
5个回答

17

以上代码的简化版本:

var filePath = @"C:\Users\Matt\Desktop\Eve Spread Sheet\Auto-Manufacture.csv";
var data = File.ReadLines(filePath).Select(x => x.Split(',')).ToArray();

注意使用ReadLines而不是ReadAllLines,根据MSDN文档,这种方式在处理大文件时更高效:

当您使用ReadLines时,您可以在整个集合返回之前开始枚举字符串集合;当您使用ReadAllLines时,您必须等待整个字符串数组被返回后才能访问该数组。因此,在处理非常大的文件时,ReadLines可能更加高效。


但是由于我们立即转换为数组,因此在这里没有任何区别。 - Pavel Bastov
2
这个解决方案和 Khan 的一样存在问题。x.Split() 会在单元格数据包含逗号时分割它。 - Martin
很棒的解决方案,我找到的最短代码行。 - kenneth

12

在你的代码中没有及时获取文件中行数,以供使用。

Line.Length 表示 csv 文件中列数,但看起来你也试图将其用于指定文件中行数。

以下代码应该可以得到你期望的结果:

string filePath = @"C:\Users\Matt\Desktop\Eve Spread Sheet\Auto-Manufacture.csv";
StreamReader sr = new StreamReader(filePath);
var lines = new List<string[]>();
int Row = 0;
while (!sr.EndOfStream)
{
    string[] Line = sr.ReadLine().Split(',');
    lines.Add(Line);
    Row++;
    Console.WriteLine(Row);
}

var data = lines.ToArray();

3
这不是一个健壮的解决方案。假设你有这些数据:1、2、"你看,这是文本。" 使用.Split()函数的输出将包含5个项目,而不是3个。 - Martin
取决于数据。如果您知道它处理的数据不会包含逗号,那么这样做应该是可以的。 - user2924019
出于这个原因,我总是将我的CSV默认更改为管道“|”分隔的文件格式。 - JeffS
这个无法处理带逗号的单元格,例如:data1,data2,data3,“带有逗号的数据”,data5。 - Rubén Ruíz

4

这与Pavel发布的内容相同,但它会忽略可能导致程序崩溃的空行。

var filePath = @"C:\Users\Matt\Desktop\Eve Spread Sheet\Auto-Manufacture.csv";

string[][] data = File.ReadLines(filepath).Where(line => line != "").Select(x => x.Split('|')).ToArray();

0

使用打开文件对话框

OpenFileDialog opn = new OpenFileDialog();

        if (opn.ShowDialog() == DialogResult.OK)
        {
           StreamReader sr = new StreamReader(opn.FileName);

           List<string[]> data = new List<string[]>(); 

           int Row = 0;

           while (!sr.EndOfStream)
           {
               string[] Line = sr.ReadLine().Split(',');
               data.Add(Line);
               Row++;
               Console.WriteLine(Row);
           }


        }

0

不知道你的csv文件内容,我会假设错误是由这行代码生成的:

if (Row == 0)
{
    data = new string[Line.Length, Line.Length];
}

通过将csv文件的第一行中的列数初始化为总行数,您假设行数始终等于列数。

一旦行数大于csv文件第一行的总列数,您将尝试访问不存在的行,从而导致data数组溢出。

您可以通过将data更改为列表以允许动态添加项目来简化代码:

string filePath = @"C:\Users\Matt\Desktop\Eve Spread Sheet\Auto-Manufacture.csv";
StreamReader sr = new StreamReader(filePath);
List<string> data = new List<string[]>();
int Row = 0;
while (!sr.EndOfStream)
{
    string[] Line = sr.ReadLine().Split(',');
    data.Add(Line);
    Row++;
    Console.WriteLine(Row);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接