J'écris une simple application d'importation et je dois lire un fichier CSV, afficher le résultat dans une variable DataGrid
et afficher les lignes corrompues du fichier CSV dans une autre grille. Par exemple, affichez les lignes inférieures à 5 valeurs dans une autre grille. J'essaie de faire ça comme ça:
StreamReader sr = new StreamReader(FilePath);
importingData = new Account();
string line;
string[] row = new string [5];
while ((line = sr.ReadLine()) != null)
{
row = line.Split(',');
importingData.Add(new Transaction
{
Date = DateTime.Parse(row[0]),
Reference = row[1],
Description = row[2],
Amount = decimal.Parse(row[3]),
Category = (Category)Enum.Parse(typeof(Category), row[4])
});
}
mais il est très difficile d'opérer sur des tableaux dans ce cas. Existe-t-il un meilleur moyen de diviser les valeurs?
Ne réinventez pas la roue. Tirez parti de ce qui est déjà dans .NET BCL.
Microsoft.VisualBasic
(oui, VisualBasic mais cela fonctionne aussi bien en C # - rappelez-vous qu'à la fin, il s'agit uniquement de IL)Microsoft.VisualBasic.FileIO.TextFieldParser
pour analyser le fichier CSVVoici l exemple de code:
using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv"))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
//Processing row
string[] fields = parser.ReadFields();
foreach (string field in fields)
{
//TODO: Process field
}
}
}
Cela fonctionne très bien pour moi dans mes projets C #.
Voici quelques liens/informations supplémentaires:
Mon expérience est qu'il y a beaucoup de formats différents de csv. En particulier, comment ils gèrent l'échappement des guillemets et des délimiteurs dans un champ.
Ce sont les variantes que j'ai rencontrées:
J'ai essayé beaucoup d'analyseurs syntaxiques csv existants, mais il n'y en a pas un qui puisse gérer les variantes que j'ai rencontrées. Il est également difficile de savoir à partir de la documentation quelles variantes d'échappement sont prises en charge par les analyseurs.
Dans mes projets, j'utilise maintenant le TextFieldParser VB ou un séparateur personnalisé.
Je recommande CsvHelper de Nuget .
(L'ajout d'une référence à Microsoft.VisualBasic ne vous semble pas juste, ce n'est pas seulement moche, ce n'est probablement même pas multiplateforme.)
Parfois, utiliser des bibliothèques est cool quand on ne veut pas réinventer la roue, mais dans ce cas, on peut faire le même travail avec moins de lignes de code et être plus facile à lire comparé à l’utilisation de bibliothèques ..__ Voici une approche différente que je trouve très facile à utiliser.
using (StreamReader reader = new StreamReader(fileName))
{
string line;
while ((line = reader.ReadLine()) != null)
{
//Define pattern
Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
//Separating columns to array
string[] X = CSVParser.Split(line);
/* Do something with X */
}
}
Le format CSV peut être compliqué rapidement réel.
Utilisez quelque chose de robuste et bien testé:
FileHelpers: www.filehelpers.net
FileHelpers est une bibliothèque .NET gratuite et facile à utiliser pour importer/exporter des données d’enregistrements de longueur fixe ou délimités dans des fichiers, des chaînes ou des flux .
J'utilise ceci ici:
http://www.codeproject.com/KB/database/GenericParser.aspx
La dernière fois que je cherchais quelque chose comme cela, je l’ai trouvée en réponse à cette question question .
Un autre à cette liste, Cinchoo ETL - une bibliothèque open source pour lire et écrire des fichiers CSV
Pour un exemple de fichier CSV ci-dessous
Id, Name
1, Tom
2, Mark
Rapidement, vous pouvez les charger en utilisant la bibliothèque ci-dessous
using (var reader = new ChoCSVReader("test.csv").WithFirstLineHeader())
{
foreach (dynamic item in reader)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.Name);
}
}
Si vous avez une classe POCO correspondant au fichier CSV
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
Vous pouvez l'utiliser pour charger le fichier CSV comme ci-dessous
using (var reader = new ChoCSVReader<Employee>("test.csv").WithFirstLineHeader())
{
foreach (var item in reader)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.Name);
}
}
S'il vous plaît consulter les articles à CodeProject sur la façon de l'utiliser.
Disclaimer: je suis l'auteur de cette bibliothèque
private static DataTable ConvertCSVtoDataTable(string strFilePath)
{
DataTable dt = new DataTable();
using (StreamReader sr = new StreamReader(strFilePath))
{
string[] headers = sr.ReadLine().Split(',');
foreach (string header in headers)
{
dt.Columns.Add(header);
}
while (!sr.EndOfStream)
{
string[] rows = sr.ReadLine().Split(',');
DataRow dr = dt.NewRow();
for (int i = 0; i < headers.Length; i++)
{
dr[i] = rows[i];
}
dt.Rows.Add(dr);
}
}
return dt;
}
private static void WriteToDb(DataTable dt)
{
string connectionString =
"Data Source=localhost;" +
"Initial Catalog=Northwind;" +
"Integrated Security=SSPI;";
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("spInsertTest", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@policyID", SqlDbType.Int).Value = 12;
cmd.Parameters.Add("@statecode", SqlDbType.VarChar).Value = "blagh2";
cmd.Parameters.Add("@county", SqlDbType.VarChar).Value = "blagh3";
con.Open();
cmd.ExecuteNonQuery();
}
}
}
Pour compléter les réponses précédentes, vous pouvez avoir besoin d’une collection d’objets de son fichier CSV, analysés par la méthode TextFieldParser
ou string.Split
, puis chaque ligne convertie en objet par Reflection. Évidemment, vous devez d’abord définir une classe qui correspond aux lignes du fichier CSV.
J'ai utilisé le simple sérialiseur CSV de Michael Kropat trouvé ici: Classe générique en CSV (toutes les propriétés) Et ai réutilisé ses méthodes pour obtenir les champs et les propriétés de la classe souhaitée.
Je désérialise mon fichier CSV avec la méthode suivante:
public static IEnumerable<T> ReadCsvFileTextFieldParser<T>(string fileFullPath, string delimiter = ";") where T : new()
{
if (!File.Exists(fileFullPath))
{
return null;
}
var list = new List<T>();
var csvFields = GetAllFieldOfClass<T>();
var fieldDict = new Dictionary<int, MemberInfo>();
using (TextFieldParser parser = new TextFieldParser(fileFullPath))
{
parser.SetDelimiters(delimiter);
bool headerParsed = false;
while (!parser.EndOfData)
{
//Processing row
string[] rowFields = parser.ReadFields();
if (!headerParsed)
{
for (int i = 0; i < rowFields.Length; i++)
{
// First row shall be the header!
var csvField = csvFields.Where(f => f.Name == rowFields[i]).FirstOrDefault();
if (csvField != null)
{
fieldDict.Add(i, csvField);
}
}
headerParsed = true;
}
else
{
T newObj = new T();
for (int i = 0; i < rowFields.Length; i++)
{
var csvFied = fieldDict[i];
var record = rowFields[i];
if (csvFied is FieldInfo)
{
((FieldInfo)csvFied).SetValue(newObj, record);
}
else if (csvFied is PropertyInfo)
{
var pi = (PropertyInfo)csvFied;
pi.SetValue(newObj, Convert.ChangeType(record, pi.PropertyType), null);
}
else
{
throw new Exception("Unhandled case.");
}
}
if (newObj != null)
{
list.Add(newObj);
}
}
}
}
return list;
}
public static IEnumerable<MemberInfo> GetAllFieldOfClass<T>()
{
return
from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
where new[] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType)
let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
select mi;
}
Tout d'abord besoin de comprendre ce qu'est le CSV et comment l'écrire.
/r/n
) est la prochaine ligne "table".\t
ou ,
/r/n
sybols (la cellule doit commencer par un symbole entre guillemets et se termine par ce symbole dans ce cas).Pour que C #/Visual Basic fonctionne avec des fichiers CSV, le moyen le plus simple consiste à utiliser la bibliothèque standard Microsoft.VisualBasic
. Vous devez juste ajouter la référence nécessaire et la chaîne suivante à votre classe:
using Microsoft.VisualBasic.FileIO;
Oui, vous pouvez l'utiliser en C #, ne vous inquiétez pas. Cette bibliothèque peut lire des fichiers relativement volumineux et prend en charge toutes les règles nécessaires. Vous pourrez ainsi travailler avec tous les fichiers CSV.
Il y a quelque temps, j'avais écrit un cours simple pour la lecture/écriture au format CSV basé sur cette bibliothèque. En utilisant cette classe simple, vous pourrez travailler avec CSV comme avec un tableau à 2 dimensions. Vous pouvez trouver ma classe par le lien suivant: https://github.com/ukushu/DataExporter
Exemple simple d'utilisation:
Csv csv = new Csv("\t");//delimiter symbol
csv.FileOpen("c:\\file1.csv");
var row1Cell6Value = csv.Rows[0][5];
csv.AddRow("asdf","asdffffff","5")
csv.FileSave("c:\\file2.csv");