Разбор CSV файла в 2d-массив

Я пытаюсь разобрать CSV файл в 2D-массив на С#. У меня очень странная проблема, вот мой код:

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 строк в массиве данных точно так, как ожидалось, но когда он приближается к строке data[Row, column] = Line[column]; в 16-й раз он просто вырывается из всего цикла (не удовлетворяя условию sr.EndOfStream) и не читает больше данных в массиве данных.

Может кто-нибудь объяснить, что может произойти?

Ответ 1

Ничто в вашем коде не забирает количество строк из вашего файла, чтобы использовать его.

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();

Ответ 2

Более короткая версия приведенного выше кода:

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 может быть более эффективным.

Ответ 3

Это то же самое, что и 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();

Ответ 4

Не зная содержимого вашего 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);
}

Ответ 5

С помощью диалогового окна "Открыть файл"

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);
           }


        }