Lire des fichiers CSV en utilisant C #

J’écris une application d’importation simple et je dois lire un fichier CSV, afficher le résultat dans un DataGrid et afficher les lignes corrompues du fichier CSV dans une autre grid. Par exemple, affichez les lignes plus courtes que 5 valeurs dans une autre grid. J’essaie de faire comme ça:

 StreamReader sr = new StreamReader(FilePath); importingData = new Account(); ssortingng line; ssortingng[] row = new ssortingng [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. Y a-t-il une meilleure façon de diviser les valeurs?

Ne réinventez pas la roue. Profitez de ce qui est déjà dans .NET BCL.

  • append une référence à Microsoft.VisualBasic (oui, il dit VisualBasic mais cela fonctionne aussi bien en C # – rappelez-vous qu’à la fin, il ne s’agit que d’IL)
  • utiliser la classe Microsoft.VisualBasic.FileIO.TextFieldParser pour parsingr le fichier CSV

Voici l exemple de code:

 using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv")) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); while (!parser.EndOfData) { //Processing row ssortingng[] fields = parser.ReadFields(); foreach (ssortingng field in fields) { //TODO: Process field } } } 

Cela fonctionne très bien pour moi dans mes projets C #.

Voici quelques liens / informations supplémentaires:

  • MSDN: lire des fichiers texte délimités par des virgules dans Visual Basic
  • MSDN: Classe TextFieldParser

Mon expérience est qu’il existe de nombreux formats de csv. Spécifiquement comment ils gèrent la fuite des guillemets et des délimiteurs dans un champ.

Ce sont les variantes que j’ai rencontrées:

  • les guillemets sont cotés et doublés (excel) c’est-à-dire 15 “-> field1,” 15 “” “, field3
  • les citations ne sont pas modifiées à moins que le champ ne soit cité pour une autre raison. soit 15 “-> champ1,15”, champs3
  • les guillemets sont échappés avec \. à savoir 15 “-> champ1,” 15 \ “”, champ3
  • les citations ne sont pas du tout modifiées (ce n’est pas toujours possible d’parsingr correctement)
  • le délimiteur est cité (excel). c’est-à-dire a, b -> champ1, “a, b”, champ3
  • le délimiteur est échappé avec \. c’est-à-dire a, b -> champ1, a \, b, champ3

J’ai essayé de nombreux parsingurs csv existants, mais il n’y en a pas un seul capable de gérer les variantes que j’ai rencontrées. Il est également difficile de trouver dans la documentation les variantes qui échappent aux parseurs.

Dans mes projets, j’utilise maintenant soit VB TextFieldParser, soit un séparateur personnalisé.

Je recommande CsvHelper de Nuget .

(Ajouter une référence à Microsoft.VisualBasic ne semble pas correct, ce n’est pas seulement moche, ce n’est probablement pas même multi-plateforme.)

Parfois, l’utilisation de bibliothèques est cool lorsque vous ne voulez pas réinventer la roue, mais dans ce cas, vous pouvez faire le même travail avec moins de lignes de code et plus facile à lire que d’utiliser des bibliothèques. Voici une approche différente que je trouve très facile à utiliser.

  1. Dans cet exemple, j’utilise StreamReader pour lire le fichier
  2. Regex pour détecter le délimiteur de chaque ligne.
  3. Un tableau pour collecter les colonnes de l’index 0 à n

 using (StreamReader reader = new StreamReader(fileName)) { ssortingng line; while ((line = reader.ReadLine()) != null) { //Define pattern Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))"); //Separating columns to array ssortingng[] X = CSVParser.Split(line); /* Do something with X */ } } 

Le CSV peut se compliquer très vite.

Utilisez quelque chose de robuste et bien testé:
FileHelpers: http://www.filehelpers.net

Les FileHelpers sont une bibliothèque .NET gratuite et facile à utiliser pour importer / exporter des données à partir d’enregistrements de longueur fixe ou délimités dans des fichiers, des chaînes ou des stream.

Je l’utilise ici:

http://www.codeproject.com/KB/database/GenericParser.aspx

La dernière fois que je cherchais quelque chose comme ça, je l’ai trouvé comme une réponse à cette question .

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 ssortingng Name { get; set; } } 

Vous pouvez l’utiliser pour charger le fichier CSV comme ci-dessous

 using (var reader = new ChoCSVReader("test.csv").WithFirstLineHeader()) { foreach (var item in reader) { Console.WriteLine(item.Id); Console.WriteLine(item.Name); } } 

S’il vous plaît vérifier les articles à CodeProject sur la façon de l’utiliser.

Disclaimer: Je suis l’auteur de cette bibliothèque

Tout d’abord, il faut comprendre ce qu’est le format CSV et comment l’écrire.

  1. Chaque chaîne suivante ( /r/n ) est la prochaine ligne “table”.
  2. Les cellules “Table” sont séparées par un symbole de délimiteur. Les symboles les plus souvent utilisés sont \t ou ,
  3. Chaque cellule peut éventuellement contenir ce symbole de délimiteur (la cellule doit commencer par un symbole de guillemets et se termine par ce symbole dans ce cas)
  4. Chaque cellule peut contenir /r/n sybols (la cellule doit commencer par un symbole de guillemets et se termine par ce symbole dans ce cas)

La méthode la plus simple pour que C # / Visual Basic fonctionne avec des fichiers CSV consiste à utiliser la bibliothèque standard Microsoft.VisualBasic . Il vous suffit d’append 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 donc travailler avec tous les fichiers CSV.

Il y a quelque temps, j’avais écrit une classe simple pour la lecture / écriture CSV basée 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"); 

Pour compléter les réponses précédentes, on peut avoir besoin d’une collection d’objects de son fichier CSV, soit analysés par la méthode TextFieldParser ou ssortingng.Split , puis chaque ligne est convertie en object via Reflection. Vous devez évidemment 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 à CSV (toutes les propriétés) et 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 ReadCsvFileTextFieldParser(ssortingng fileFullPath, ssortingng delimiter = ";") where T : new() { if (!File.Exists(fileFullPath)) { return null; } var list = new List(); var csvFields = GetAllFieldOfClass(); var fieldDict = new Dictionary(); using (TextFieldParser parser = new TextFieldParser(fileFullPath)) { parser.SetDelimiters(delimiter); bool headerParsed = false; while (!parser.EndOfData) { //Processing row ssortingng[] 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 GetAllFieldOfClass() { return from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) where new[] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType) let orderAttr = (ColumnOrderAtsortingbute)Atsortingbute.GetCustomAtsortingbute(mi, typeof(ColumnOrderAtsortingbute)) orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name select mi; } 
 private static DataTable ConvertCSVtoDataTable(ssortingng strFilePath) { DataTable dt = new DataTable(); using (StreamReader sr = new StreamReader(strFilePath)) { ssortingng[] headers = sr.ReadLine().Split(','); foreach (ssortingng header in headers) { dt.Columns.Add(header); } while (!sr.EndOfStream) { ssortingng[] 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(); } } }