c# – Importazione dati da file CSV

Per tutti quelli come me, che ogni tanto hanno bisogno di implementare delle funzionalità nelle proprie applicazioni, per importare dei dati tabellari tramite il formato csv, questa semplice classe può tornare utile.

L’ utilizzo è abbastanza semplice, il tutto si traduce nella conversione del vostro csv in un comodo DataTable per le vostre successive elaborazioni:

DataTable dt = CSVParser.Parse(content, true, ',');

content rappresenta il contenuto del vostro file csv, poi dovrete indicare se nel file è presente o meno l’header delle colonne e quale separatore si sta usando.

using System.Text;
using System.Data;
using System.IO;
using System.Collections;

public class CSVParser
{
public static DataTable Parse(string data, bool headers, char separator)
{
return Parse(new StringReader(data), headers, separator);
}

public static DataTable Parse(string data)
{
return Parse(new StringReader(data));
}

public static DataTable Parse(TextReader stream)
{
return Parse(stream, false, ';');
}

public static DataTable Parse(TextReader stream, bool headers, char separator)
{
DataTable table = new DataTable();
CSVStream csv = new CSVStream(stream);
string[] row = csv.GetNextRow(separator);
if (row == null)
return null;
if (headers)
{
foreach (string header in row)
{
if (header != null && header.Length > 0 && !table.Columns.Contains(header))
table.Columns.Add(header, typeof (string));
else
table.Columns.Add(GetNextColumnHeader(table), typeof (string));
}
row = csv.GetNextRow(separator);
}
while (row != null)
{
while (row.Length > table.Columns.Count)
table.Columns.Add(GetNextColumnHeader(table), typeof (string));
table.Rows.Add(row);
row = csv.GetNextRow(separator);
}
return table;
}

private static string GetNextColumnHeader(DataTable table)
{
int c = 1;
while (true)
{
string h = "Column" + c++;
if (!table.Columns.Contains(h))
return h;
}
}

private class CSVStream
{
private TextReader stream;

public CSVStream(TextReader s)
{
stream = s;
}

public string[] GetNextRow(char separator)
{
ArrayList row = new ArrayList();
while (true)
{
string item = GetNextItem(separator);
if (item == null)
return row.Count == 0 ? null : (string[]) row.ToArray(typeof (string));
row.Add(item);
}
}

private bool EOS = false;
private bool EOL = false;

private string GetNextItem(char separator)
{
if (EOL)
{
// previous item was last in line, start new line
EOL = false;
return null;
}

bool quoted = false;
bool predata = true;
bool postdata = false;
StringBuilder item = new StringBuilder();

while (true)
{
char c = GetNextChar(true);
if (EOS)
return item.Length > 0 ? item.ToString() : null;

if ((postdata || !quoted) && c == separator)
// end of item, return
return item.ToString();

if ((predata || postdata || !quoted) && (c == '\x0A' || c == '\x0D'))
{
// we are at the end of the line, eat newline characters and exit
EOL = true;
if (c == '\x0D' && GetNextChar(false) == '\x0A')
// new line sequence is 0D0A
GetNextChar(true);
return item.ToString();
}

if (predata && c == ' ')
// whitespace preceeding data, discard
continue;

if (predata && c == '"')
{
// quoted data is starting
quoted = true;
predata = false;
continue;
}

if (predata)
{
// data is starting without quotes
predata = false;
item.Append(c);
continue;
}

if (c == '"' && quoted)
{
if (GetNextChar(false) == '"')
// double quotes within quoted string means add a quote
item.Append(GetNextChar(true));
else
// end-quote reached
postdata = true;
continue;
}

// all cases covered, character must be data
item.Append(c);
}
}

private char[] buffer = new char[4096];
private int pos = 0;
private int length = 0;

private char GetNextChar(bool eat)
{
if (pos >= length)
{
length = stream.ReadBlock(buffer, 0, buffer.Length);
if (length == 0)
{
EOS = true;
return '\0';
}
pos = 0;
}
if (eat)
return buffer[pos++];
else
return buffer[pos];
}
}
}


Commenti

Post popolari in questo blog

c# – Semplice hack per risolvere un bug in function ValidatorOnChange(event)

CineTrailer per Android