Чтение CSV файла и сохранение значений в массиве
Я пытаюсь прочитать файл *.csv
.
Файл *.csv
состоит из двух столбцов, разделенных точкой с запятой ( ";" ).
Я могу читать *.csv
файл с помощью StreamReader и умею отделять каждую строку с помощью функции Split()
. Я хочу сохранить каждый столбец в отдельный массив, а затем отобразить его.
Можно ли это сделать?
Ответы
Ответ 1
Вы можете сделать это следующим образом:
using System.IO;
static void Main(string[] args)
{
using(var reader = new StreamReader(@"C:\test.csv"))
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
listA.Add(values[0]);
listB.Add(values[1]);
}
}
}
Ответ 2
Мой любимый парсер csv встроен в библиотеку.net. Это скрытое сокровище в пространстве имен Microsoft.VisualBasic. Ниже приведен пример кода:
using Microsoft.VisualBasic.FileIO;
var path = @"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
// Skip the row with the column names
csvParser.ReadLine();
while (!csvParser.EndOfData)
{
// Read current line fields, pointer moves to the next line.
string[] fields = csvParser.ReadFields();
string Name = fields[0];
string Address = fields[1];
}
}
Не забудьте добавить ссылку на Microsoft.VisualBasic
Более подробная информация о парсере приведена здесь: http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
Ответ 3
Способ LINQ:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^ Неверно - Редактировать Nick
Похоже, что первоначальный ответчик пытался заполнить csv
2-мерным массивом - массивом, содержащим массивы. Каждый элемент в первом массиве содержит массив, представляющий этот номер строки, с каждым элементом в вложенном массиве, содержащим данные для этого конкретного столбца.
var csv = from line in lines
select (line.Split(',')).ToArray();
Ответ 4
Обычно я использую этот парсер из codeproject, так как там есть куча символов, которые схожи с ним, и которые он обрабатывает для меня.
Ответ 5
Просто наткнулся на эту библиотеку: https://github.com/JoshClose/CsvHelper
Очень интуитивно понятный и простой в использовании. Имеет также пакет nuget, который был выполнен: http://nuget.org/packages/CsvHelper/1.17.0. Также, похоже, активно поддерживается, что мне нравится.
Конфигурировать его для использования в виде двоеточия легко: https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations
Ответ 6
Вот мой вариант ответа на верхний голос:
var contents = File.ReadAllText(filename).Split('\n');
var csv = from line in contents
select line.Split(',').ToArray();
Затем переменную csv
можно использовать, как в следующем примере:
int headerRows = 5;
foreach (var row in csv.Skip(headerRows)
.TakeWhile(r => r.Length > 1 && r.Last().Trim().Length > 0))
{
String zerothColumnValue = row[0]; // leftmost column
var firstColumnValue = row[1];
}
Ответ 7
Вы не можете сразу создать массив, потому что вам нужно знать количество строк с начала (а для этого потребуется дважды прочитать файл csv)
Вы можете хранить значения в двух List<T>
и затем использовать их или преобразовывать в массив с помощью List<T>.ToArray()
Очень простой пример:
var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader("filename.csv"))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(';');
column1.Add(splits[0]);
column2.Add(splits[1]);
}
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
Console.WriteLine(element);
// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
Console.WriteLine(element);
NB
Обратите внимание, что это просто очень простой пример. Использование string.Split
не учитывает случаи, когда некоторые записи содержат разделитель ;
внутри него.
Для более безопасного подхода рассмотрите возможность использования некоторых специфичных для csv библиотек, таких как CsvHelper, в nuget.
Ответ 8
Если вам нужно пропустить строки (head-) и/или столбцы, вы можете использовать это для создания двумерного массива:
var lines = File.ReadAllLines(path).Select(a => a.Split(';'));
var csv = (from line in lines
select (from col in line
select col).Skip(1).ToArray() // skip the first column
).Skip(2).ToArray(); // skip 2 headlines
Это очень полезно, если вам нужно сформировать данные, прежде чем обрабатывать их дальше (предполагая, что первые 2 строки состоят из заголовка, а первый столбец - это заголовок строки, который вам не нужно иметь в массиве потому что вы просто хотите рассматривать данные).
N.B. Вы можете легко получить заголовки и 1-й столбец, используя следующий код:
var coltitle = (from line in lines
select line.Skip(1).ToArray() // skip 1st column
).Skip(1).Take(1).FirstOrDefault().ToArray(); // take the 2nd row
var rowtitle = (from line in lines select line[0] // take 1st column
).Skip(2).ToArray(); // skip 2 headlines
В этом примере кода предполагается следующая структура вашего файла *.csv
:
![CSV Matrix]()
Примечание. Если вам нужно пропустить пустые строки, что иногда может быть полезно, вы можете сделать это, вставив
where line.Any(a=>!string.IsNullOrWhiteSpace(a))
между инструкциями from
и select
в приведенных выше примерах LINQ.
Ответ 9
Вы можете использовать dll Microsoft.VisualBasic.FileIO.TextFieldParser в С# для лучшей производительности
получить ниже пример кода из вышеприведенной статьи
static void Main()
{
string [email protected]"C:\Users\Administrator\Desktop\test.csv";
DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
Console.WriteLine("Rows count:" + csvData.Rows.Count);
Console.ReadLine();
}
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
}
return csvData;
}
Ответ 10
var firstColumn = new List<string>();
var lastColumn = new List<string>();
// your code for reading CSV file
foreach(var line in file)
{
var array = line.Split(';');
firstColumn.Add(array[0]);
lastColumn.Add(array[1]);
}
var firstArray = firstColumn.ToArray();
var lastArray = lastColumn.ToArray();
Ответ 11
Здесь специальный случай, когда одно из полей данных имеет точку с запятой ( ";" ) как часть данных, в этом случае большинство ответов выше не будет выполнено.
Решение этого случая будет
string[] csvRows = System.IO.File.ReadAllLines(FullyQaulifiedFileName);
string[] fields = null;
List<string> lstFields;
string field;
bool quoteStarted = false;
foreach (string csvRow in csvRows)
{
lstFields = new List<string>();
field = "";
for (int i = 0; i < csvRow.Length; i++)
{
string tmp = csvRow.ElementAt(i).ToString();
if(String.Compare(tmp,"\"")==0)
{
quoteStarted = !quoteStarted;
}
if (String.Compare(tmp, ";") == 0 && !quoteStarted)
{
lstFields.Add(field);
field = "";
}
else if (String.Compare(tmp, "\"") != 0)
{
field += tmp;
}
}
if(!string.IsNullOrEmpty(field))
{
lstFields.Add(field);
field = "";
}
// This will hold values for each column for current row under processing
fields = lstFields.ToArray();
}
Ответ 12
Привет всем, я создал для этого статический класс.
+ проверка столбца
+ удаление квоты
public static class CSV
{
public static List<string[]> Import(string file, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
{
return ReadCSVFile(file, csvDelimiter, ignoreHeadline, removeQuoteSign);
}
private static List<string[]> ReadCSVFile(string filename, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
{
string[] result = new string[0];
List<string[]> lst = new List<string[]>();
string line;
int currentLineNumner = 0;
int columnCount = 0;
// Read the file and display it line by line.
using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
{
while ((line = file.ReadLine()) != null)
{
currentLineNumner++;
string[] strAr = line.Split(csvDelimiter);
// save column count of dirst line
if (currentLineNumner == 1)
{
columnCount = strAr.Count();
}
else
{
//Check column count of every other lines
if (strAr.Count() != columnCount)
{
throw new Exception(string.Format("CSV Import Exception: Wrong column count in line {0}", currentLineNumner));
}
}
if (removeQuoteSign) strAr = RemoveQouteSign(strAr);
if (ignoreHeadline)
{
if(currentLineNumner !=1) lst.Add(strAr);
}
else
{
lst.Add(strAr);
}
}
}
return lst;
}
private static string[] RemoveQouteSign(string[] ar)
{
for (int i = 0;i< ar.Count() ; i++)
{
if (ar[i].StartsWith("\"") || ar[i].StartsWith("'")) ar[i] = ar[i].Substring(1);
if (ar[i].EndsWith("\"") || ar[i].EndsWith("'")) ar[i] = ar[i].Substring(0,ar[i].Length-1);
}
return ar;
}
}
Ответ 13
Библиотека с открытым исходным кодом Angara.Table позволяет загружать CSV в типизированные столбцы, поэтому вы можете получить массивы из столбцов. Каждый столбец можно индексировать как по имени, так и по индексу. См. http://predictionmachines.github.io/Angara.Table/saveload.html.
Библиотека соответствует RFC4180 для CSV; он позволяет вводить типы и многострочные строки.
Пример:
using System.Collections.Immutable;
using Angara.Data;
using Angara.Data.DelimitedFile;
...
ReadSettings settings = new ReadSettings(Delimiter.Semicolon, false, true, null, null);
Table table = Table.Load("data.csv", settings);
ImmutableArray<double> a = table["double-column-name"].Rows.AsReal;
for(int i = 0; i < a.Length; i++)
{
Console.WriteLine("{0}: {1}", i, a[i]);
}
Вы можете увидеть тип столбца, используя тип Column, например
Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);
Поскольку библиотека сосредоточена на F #, вам может потребоваться добавить ссылку на сборку FSharp.Core 4.4; нажмите "Добавить ссылку" в проекте и выберите "FSHarp.Core 4.4" в разделе "Ассембли" → "Расширения".
Ответ 14
Я использую csvreader.com(платный компонент) в течение многих лет, и у меня никогда не было проблемы. Он прочный, маленький и быстрый, но вам придется заплатить за него. Вы можете установить разделитель на все, что вам нравится.
using (CsvReader reader = new CsvReader(s) {
reader.Settings.Delimiter = ';';
reader.ReadHeaders(); // if headers on a line by themselves. Makes reader.Headers[] available
while (reader.ReadRecord())
... use reader.Values[col_i] ...
}
Ответ 15
Я просто студент, работающий над моей магистерской диссертацией, но так я решил это, и это сработало для меня. Сначала вы выбираете файл из каталога (только в формате csv), а затем помещаете данные в списки.
List<float> t = new List<float>();
List<float> SensorI = new List<float>();
List<float> SensorII = new List<float>();
List<float> SensorIII = new List<float>();
using (OpenFileDialog dialog = new OpenFileDialog())
{
try
{
dialog.Filter = "csv files (*.csv)|*.csv";
dialog.Multiselect = false;
dialog.InitialDirectory = ".";
dialog.Title = "Select file (only in csv format)";
if (dialog.ShowDialog() == DialogResult.OK)
{
var fs = File.ReadAllLines(dialog.FileName).Select(a => a.Split(';'));
int counter = 0;
foreach (var line in fs)
{
counter++;
if (counter > 2) // Skip first two headder lines
{
this.t.Add(float.Parse(line[0]));
this.SensorI.Add(float.Parse(line[1]));
this.SensorII.Add(float.Parse(line[2]));
this.SensorIII.Add(float.Parse(line[3]));
}
}
}
}
catch (Exception exc)
{
MessageBox.Show(
"Error while opening the file.\n" + exc.Message,
this.Text,
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
}
Ответ 16
Все еще неправильно. Вы должны компенсировать "" в кавычках.
Вот мое решение csv в стиле Microsoft.
/// <summary>
/// Microsoft style csv file. " is the quote character, "" is an escaped quote.
/// </summary>
/// <param name="fileName"></param>
/// <param name="sepChar"></param>
/// <param name="quoteChar"></param>
/// <param name="escChar"></param>
/// <returns></returns>
public static List<string[]> ReadCSVFileMSStyle(string fileName, char sepChar = ',', char quoteChar = '"')
{
List<string[]> ret = new List<string[]>();
string[] csvRows = System.IO.File.ReadAllLines(fileName);
foreach (string csvRow in csvRows)
{
bool inQuotes = false;
List<string> fields = new List<string>();
string field = "";
for (int i = 0; i < csvRow.Length; i++)
{
if (inQuotes)
{
// Is it a "" inside quoted area? (escaped litteral quote)
if(i < csvRow.Length - 1 && csvRow[i] == quoteChar && csvRow[i+1] == quoteChar)
{
i++;
field += quoteChar;
}
else if(csvRow[i] == quoteChar)
{
inQuotes = false;
}
else
{
field += csvRow[i];
}
}
else // Not in quoted region
{
if (csvRow[i] == quoteChar)
{
inQuotes = true;
}
if (csvRow[i] == sepChar)
{
fields.Add(field);
field = "";
}
else
{
field += csvRow[i];
}
}
}
if (!string.IsNullOrEmpty(field))
{
fields.Add(field);
field = "";
}
ret.Add(fields.ToArray());
}
return ret;
}
}
Ответ 17
У меня есть библиотека, которая делает именно то, что вам нужно.
Некоторое время назад я написал простую и достаточно быструю библиотеку для работы с CSV файлами. Вы можете найти его по следующей ссылке: https://github.com/ukushu/DataExporter
Он работает с CSV как с 2-х мерным массивом. Точно так же, как вам нужно.
Например, в случае, если вам нужны все значения 3-й строки, вам нужно написать:
Csv csv = new Csv();
csv.FileOpen("c:\\file1.csv");
var allValuesOf3rdRow = csv.Rows[2];
или прочитать 2-ю ячейку
var value = csv.Rows[2][1];
Ответ 18
Я потратил несколько часов на поиск подходящей библиотеки, но, наконец, я написал свой собственный код :) Вы можете читать файлы (или базы данных) любыми инструментами, которые вам нужны, а затем применять следующую процедуру к каждой строке:
private static string[] SmartSplit(string line, char separator = ',')
{
var inQuotes = false;
var token = "";
var lines = new List<string>();
for (var i = 0; i < line.Length; i++) {
var ch = line[i];
if (inQuotes) // process string in quotes,
{
if (ch == '"') {
if (i<line.Length-1 && line[i + 1] == '"') {
i++;
token += '"';
}
else inQuotes = false;
} else token += ch;
} else {
if (ch == '"') inQuotes = true;
else if (ch == separator) {
lines.Add(token);
token = "";
} else token += ch;
}
}
lines.Add(token);
return lines.ToArray();
}