c# - parser - Leyendo el archivo CSV y almacenando valores en una matriz
read csv c# streamreader (17)
Acabo de encontrar esta biblioteca: https://github.com/JoshClose/CsvHelper
Muy intuitivo y fácil de usar. También tiene un paquete nuget que se implementa rápidamente: http://nuget.org/packages/CsvHelper/1.17.0 . También parece que se mantiene activamente lo que me gusta.
Configurarlo para usar un punto y coma es fácil: https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations
Estoy tratando de leer un archivo *.csv
.
El archivo *.csv
consta de dos columnas separadas por punto y coma (" ; ").
Puedo leer el archivo *.csv
usando StreamReader y puedo separar cada línea usando la función Split()
. Quiero almacenar cada columna en una matriz separada y luego mostrarla.
¿Es posible hacer eso?
Aquí está mi variación de la respuesta más votada:
var contents = File.ReadAllText(filename).Split(''/n'');
var csv = from line in contents
select line.Split('','').ToArray();
La variable csv
se puede usar como en el siguiente ejemplo:
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];
}
Aquí hay un caso especial en el que uno de los campos de datos tiene un punto y coma (";") como parte de sus datos; en ese caso, la mayoría de las respuestas anteriores fallarán.
Solución es que ese caso será
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();
}
Forma LINQ:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split('';''));
var csv = from line in lines
select (from piece in line
select piece);
^^ Incorrecto - Editado por Nick
Parece que el contestador original estaba intentando rellenar csv
con una matriz bidimensional, una matriz que contiene matrices. Cada elemento de la primera matriz contiene una matriz que representa ese número de línea con cada elemento de la matriz anidada que contiene los datos para esa columna específica.
var csv = from line in lines
select (line.Split('','')).ToArray();
He estado usando csvreader.com (componente de pago) durante años, y nunca he tenido un problema. Es sólido, pequeño y rápido, pero tienes que pagarlo. Puedes configurar el delimitador a lo que quieras.
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] ...
}
La biblioteca de código abierto Angara.Table permite cargar CSV en columnas escritas, para que pueda obtener los arreglos de las columnas. Cada columna puede ser indexada tanto por nombre como por índice. Consulte http://predictionmachines.github.io/Angara.Table/saveload.html .
La biblioteca sigue RFC4180 para CSV; Permite la inferencia de tipos y cadenas multilínea.
Ejemplo:
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]);
}
Puede ver un tipo de columna utilizando el tipo Columna, por ejemplo,
Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);
Dado que la biblioteca está enfocada en F #, es posible que necesite agregar una referencia al ensamblaje de FSharp.Core 4.4; haga clic en ''Agregar referencia'' en el proyecto y elija FSharp.Core 4.4 en "Ensamblados" -> "Extensiones".
Mi analizador csv favorito es uno integrado en la biblioteca .net. Este es un tesoro escondido dentro del espacio de nombres Microsoft.VisualBasic. A continuación se muestra un código de ejemplo:
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];
}
}
Recuerde agregar referencia a Microsoft.VisualBasic
Más detalles sobre el analizador se dan aquí: http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
No puede crear una matriz inmediatamente porque necesita saber la cantidad de filas desde el principio (y esto requeriría leer el archivo csv dos veces)
Puede almacenar valores en dos List<T>
y luego usarlos o convertirlos en una matriz utilizando List<T>.ToArray()
Ejemplo muy simple:
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);
Puede usar Microsoft.VisualBasic.FileIO.TextFieldParser dll en C # para un mejor rendimiento
Obtener el ejemplo de código de abajo del artículo anterior
static void Main()
{
string csv_file_path=@"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;
}
Puedes hacerlo así:
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]);
}
}
}
Si necesita omitir (encabezados) líneas y / o columnas, puede usar esto para crear una matriz bidimensional:
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
Esto es bastante útil si necesita dar forma a los datos antes de continuar procesándolos (asumiendo que las primeras 2 líneas consisten en el título, y la primera columna es un título de fila, que no necesita tener en la matriz porque simplemente Quiero tener en cuenta los datos).
NB Puede obtener fácilmente los titulares y la primera columna utilizando el siguiente código:
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
Este ejemplo de código asume la siguiente estructura de su archivo *.csv
:
Nota: Si necesita omitir filas vacías, lo que a veces puede ser útil, puede hacerlo insertando
where line.Any(a=>!string.IsNullOrWhiteSpace(a))
entre la declaración from
y la select
en los ejemplos de código LINQ anteriores.
Sigue siendo incorrecto. Necesitas compensar por "" entre comillas. Aquí está mi solución de estilo Microsoft csv.
/// <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;
}
}
Solo soy un estudiante que está trabajando en mi tesis de maestría, pero esta es la forma en que la resolví y funcionó bien para mí. Primero seleccione su archivo del directorio (solo en formato csv) y luego coloque los datos en las listas.
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
);
}
}
Tengo una biblioteca que está haciendo exactamente lo que necesita.
Hace algún tiempo escribí una biblioteca simple y lo suficientemente rápida para trabajar con archivos CSV. Puede encontrarlo en el siguiente enlace: https://github.com/ukushu/DataExporter
Funciona con CSV como con 2 dimensiones array. Exactamente como usted necesita.
Como ejemplo, en caso de que necesite todos los valores de la tercera fila, solo necesita escribir:
Csv csv = new Csv();
csv.FileOpen("c://file1.csv");
var allValuesOf3rdRow = csv.Rows[2];
o para leer la segunda celda de
var value = csv.Rows[2][1];
Usualmente uso este analizador de código de proyecto , ya que hay un montón de escapes de personajes y similares que maneja para mí.
Hola a todos, creé una clase estática para hacer esto. + verificación de columna + eliminación de signo de cuota
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;
}
}
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();