Kapela.Tools.Csv
10.2.0
Prefix Reserved
dotnet add package Kapela.Tools.Csv --version 10.2.0
NuGet\Install-Package Kapela.Tools.Csv -Version 10.2.0
<PackageReference Include="Kapela.Tools.Csv" Version="10.2.0" />
<PackageVersion Include="Kapela.Tools.Csv" Version="10.2.0" />
<PackageReference Include="Kapela.Tools.Csv" />
paket add Kapela.Tools.Csv --version 10.2.0
#r "nuget: Kapela.Tools.Csv, 10.2.0"
#:package Kapela.Tools.Csv@10.2.0
#addin nuget:?package=Kapela.Tools.Csv&version=10.2.0
#tool nuget:?package=Kapela.Tools.Csv&version=10.2.0
📦 Kapela.Tools.Csv
Bibliothèque .NET pour la sérialisation, la désérialisation, l'import et l'export de fichiers CSV.
🚀 Installation
dotnet add package Kapela.Tools.Csv
⚠️ Breaking changes
Cette version est non rétrocompatible avec les versions inférieures à 10.1.0.
| Élément modifié | Avant | Après |
|---|---|---|
CsvSerializer n'hérite plus de CsvSerializerOptions — les options sont regroupées dans Options |
csv.Separator = ';'; |
services.AddKapelaCsvSerializer(o => { o.Separator = ';'; }); |
FieldsMapping et CustomHeader déplacés vers les options |
csv.Serialize(list, fieldsMapping: "Col1;Col2") |
services.AddKapelaCsvSerializer(o => { o.FieldsMapping = "Col1;Col2"; }); |
Validate() n'accepte plus de paramètre rules |
csv.Validate(content, rules) |
services.AddKapelaCsvSerializer(o => { o.ValidationRules = [...]; }); |
SetFormatter<T>() supprimé — utiliser Options.Formatters avec CsvFormatterType |
csv.SetFormatter<decimal>(new CsvFieldFormatter { ... }) |
options.Formatters = [new CsvFieldFormatter { Type = CsvFormatterType.Decimal, ... }] |
Options.Formatters et Options.ValidationRules sont maintenant IReadOnlyList<T> |
options.Formatters.Add(...) |
Assigner la liste complète à l'enregistrement |
CsvFieldFormatter et CsvValidationRule convertis en record — propriétés init |
var f = new CsvFieldFormatter(); f.Format = "N2"; |
var f = new CsvFieldFormatter { Format = "N2" }; |
💉 Injection de dépendances
L'approche recommandée est d'enregistrer CsvSerializer dans le conteneur d'injection de dépendances, puis de le recevoir par le constructeur.
// Instance par défaut (Transient)
services.AddKapelaCsvSerializer();
// Avec configuration
services.AddKapelaCsvSerializer(options =>
{
options.Separator = ',';
options.Culture = new CultureInfo("en-US");
});
// Depuis IConfiguration (section "CsvSerializer" par défaut)
services.AddKapelaCsvSerializer(configuration);
// Réception par le constructeur
public class MonService(CsvSerializer csv)
{
public void Exporter(IEnumerable<MonObjet> liste)
{
var content = csv.Serialize(liste);
csv.ExportToFile(content, "export.csv");
}
}
🏷️ Instances nommées
// Enregistrement
services.AddKapelaCsvSerializer("Import", options => { options.Separator = ';'; });
services.AddKapelaCsvSerializer("Export", options => { options.Separator = ','; });
// Réception via la factory
public class MonService(CsvSerializerFactory factory)
{
private readonly CsvSerializer _import = factory.CreateCsvSerializer("Import");
private readonly CsvSerializer _export = factory.CreateCsvSerializer("Export");
}
📄 Configuration depuis appsettings.json
La section "CsvSerializer" est interprétée automatiquement selon sa structure.
Instance par défaut — la section contient directement les propriétés de configuration :
{
"CsvSerializer": {
"Separator": ";",
"Culture": "fr-FR",
"HasHeader": true,
"RemoveEmptyLines": true,
"Mode": "Strict",
"FieldsMapping": "Nom;Prenom;Age",
"CustomHeader": "Nom de famille;Prénom;Âge",
"ValidationRules": [
{ "Index": 0, "RegEx": "^\\d+$", "RegexLabel": "Numérique" }
],
"Formatters": [
{ "Type": "datetime", "Format": "yyyy-MM-dd" },
{ "Type": "decimal", "FieldName": "Montant", "Format": "N2" }
],
"ErrorMessages": {
"FieldCountMismatch": "Column count {0} differs from header {1}",
"TypeMismatch": "Cannot convert '{0}' to '{1}' for '{2}'",
"RegexFailed": "Field '{0}' does not match rule '{1}'",
"UnsupportedType": "Unsupported property type '{0}'"
},
"NewLineReplacement": ". "
}
}
Les valeurs de
"Type"correspondent aux constantes deCsvFormatterTypeet sont insensibles à la casse.
Instances nommées — la section contient des sous-sections dont chaque clé devient un nom d'instance :
{
"CsvSerializer": {
"Export": { "Separator": ",", "Culture": "en-US" },
"Import": { "Separator": "|" }
}
}
// Un seul appel enregistre toutes les instances nommées
services.AddKapelaCsvSerializer(configuration);
**Attention 😗* ne pas nommer une instance avec un nom réservé (
Separator,Culture,HasHeader,RemoveEmptyLines,Mode,ValidationRules,Formatters,FieldsMapping,CustomHeader,ErrorMessages,NewLineReplacement). Ces noms sont utilisés pour détecter automatiquement si la section contient une instance par défaut ou des instances nommées.
⚙️ Configuration
Toutes les options sont accessibles via la propriété Options du CsvSerializer injecté.
| Propriété | Type | Défaut | Description |
|---|---|---|---|
Separator |
char |
; |
Séparateur de champs |
Culture |
CultureInfo |
fr-FR |
Culture utilisée pour les conversions numériques et dates |
HasHeader |
bool |
true |
Indique si le CSV contient une ligne d'entête |
RemoveEmptyLines |
bool |
true |
Supprime les lignes vides à l'import |
Mode |
CsvSerializerMode |
Strict |
Mode de désérialisation (Strict ou Mapping) |
FieldsMapping |
string? |
null |
Sélection et ordre des colonnes (ex : "Nom;Prenom;Age") |
CustomHeader |
string? |
null |
Entête personnalisée à la place de l'entête générée automatiquement |
ValidationRules |
IReadOnlyList<CsvValidationRule> |
[] |
Règles de validation appliquées par Validate() |
Formatters |
IReadOnlyList<CsvFieldFormatter> |
[] |
Formatters de champs |
ErrorMessages |
CsvErrorMessages |
(messages FR) | Messages d'erreur (personnalisables pour l'internationalisation) |
NewLineReplacement |
string |
". " |
Chaîne de remplacement des retours à la ligne dans les champs quotés à l'import |
📦 CsvContent — le type central
CsvContent est l'objet pivot du package. Toutes les opérations produisent ou consomment un CsvContent :
Serialize ──► CsvContent ──► ExportToFile / ToBinary / ToString
ImportFromFile / ImportFromBinary / ImportFromString ──► CsvContent ──► Deserialize / Validate
Il représente un contenu CSV en mémoire sous forme d'une liste de lignes (string).
Propriétés
| Propriété | Type | Description |
|---|---|---|
FullContent |
IList<string> |
Toutes les lignes (entête incluse si présente) |
Header |
string |
Première ligne si le CSV a une entête, sinon chaîne vide |
Content |
IEnumerable<string> |
Lignes de données (sans l'entête) |
Méthodes
CsvContent content = csv.Serialize(maListe);
// En chaîne de caractères
string texte = content.ToString();
// En tableau d'octets (incluant le BOM si l'encoding en possède un)
byte[] octets = content.ToBinary();
byte[] octetsUtf8 = content.ToBinary(Encoding.UTF8);
// Accès aux lignes
string entete = content.Header;
IEnumerable<string> lignes = content.Content;
📤 Sérialisation
Dans les exemples suivants,
csvest une instance deCsvSerializerreçue par injection de dépendances.
CsvContent content = csv.Serialize(maListe);
Sélectionner et ordonner les colonnes
csv.Options.FieldsMapping = "Nom;Prenom;Age";
CsvContent content = csv.Serialize(maListe);
Entête personnalisée
csv.Options.CustomHeader = "Nom de famille;Prénom;Âge";
CsvContent content = csv.Serialize(maListe);
📥 Désérialisation
CsvDeserializationResult<MonObjet> result = csv.Deserialize<MonObjet>(content);
foreach (var item in result.Datas)
Console.WriteLine(item.Nom);
foreach (var error in result.Errors)
Console.WriteLine(error);
Types supportés
| Type | Nullable | Notes |
|---|---|---|
string |
— | Valeur brute |
int |
int? |
NumberStyles.Any, culture-aware |
decimal |
decimal? |
NumberStyles.Any, culture-aware |
DateTime |
DateTime? |
Format exact (via formatter), OLE Automation, ou culture-aware |
bool |
bool? |
BoolTrueValue/BoolFalseValue via formatter, ou Boolean.TryParse |
Guid |
Guid? |
Format "D" par défaut, configurable ("N", "B", "P", "X") |
| Enums | Enum? |
Par nom (insensible à la casse) ou par valeur numérique |
🔀 Modes de désérialisation
| Mode | Comportement |
|---|---|
Strict (défaut) |
Mappe colonne par colonne dans l'ordre. Génère une erreur si le nombre de champs ne correspond pas. |
Mapping |
Mappe par nom d'entête. Tolère les colonnes manquantes ou supplémentaires. |
// Via options (configuré à l'enregistrement)
services.AddKapelaCsvSerializer(options => { options.Mode = CsvSerializerMode.Mapping; });
// Via attribut sur la classe de destination (prioritaire sur les options)
[CsvSerializerMode(CsvSerializerMode.Mapping)]
public class MonObjet { ... }
📁 Import / Export
// Import depuis un fichier, un tableau d'octets ou une chaîne
var content = csv.ImportFromFile("donnees.csv");
var content2 = csv.ImportFromBinary(tableauOctets);
var content3 = csv.ImportFromString("Id;Nom\n1;Alice");
// Export (avec encoding optionnel)
csv.ExportToFile(content, "export.csv");
csv.ExportToFile(content, "export.csv", Encoding.UTF8);
🏷️ Attributs
[CsvSerializer] — sur une propriété
Personnalise l'entête ou exclut une propriété.
public class Client
{
[CsvSerializer(Header = "Identifiant")]
public int Id { get; set; }
public string Nom { get; set; }
[CsvSerializer(Ignore = true)]
public string MotDePasse { get; set; }
}
[CsvSerializerFormat] — sur une propriété
Définit le format d'un champ. Prioritaire sur les formatters globaux.
public class Commande
{
[CsvSerializerFormat(Format = "yyyy-MM-dd")]
public DateTime DateCommande { get; set; }
[CsvSerializerFormat(Format = "N2")]
public decimal Montant { get; set; }
[CsvSerializerFormat(BoolTrueValue = "OUI", BoolFalseValue = "NON")]
public bool EstValide { get; set; }
}
[CsvSerializerMode] — sur une classe
Surcharge le mode de désérialisation pour ce type spécifique.
[CsvSerializerMode(CsvSerializerMode.Mapping)]
public class MonObjet { ... }
🎨 Formatters
Les formatters s'appliquent globalement à un type ou à un champ spécifique. Ils sont définis via Options.Formatters à l'enregistrement par injection de dépendances, ou directement sur l'instance.
La propriété Type de CsvFieldFormatter doit être renseignée avec une constante de la classe CsvFormatterType :
services.AddKapelaCsvSerializer(options =>
{
options.Formatters =
[
// Toutes les dates au format yyyy-MM-dd
new CsvFieldFormatter { Type = CsvFormatterType.DateTime, Format = "yyyy-MM-dd" },
// Uniquement le champ "Montant" avec 2 décimales
new CsvFieldFormatter { Type = CsvFormatterType.Decimal, FieldName = "Montant", Format = "N2" },
// Valeurs booléennes personnalisées
new CsvFieldFormatter { Type = CsvFormatterType.Bool, BoolTrueValue = "OUI", BoolFalseValue = "NON" },
// Deux formatters pour le même type, ciblant des champs différents
new CsvFieldFormatter { Type = CsvFormatterType.Int, FieldName = "Id", Format = "D6" },
new CsvFieldFormatter { Type = CsvFormatterType.Int, FieldName = "Code", Format = "D4" }
];
});
Types disponibles
| Constante | Valeur | Type ciblé |
|---|---|---|
CsvFormatterType.Int |
"int" |
int |
CsvFormatterType.Decimal |
"decimal" |
decimal |
CsvFormatterType.DateTime |
"datetime" |
DateTime |
CsvFormatterType.Bool |
"bool" |
bool |
CsvFormatterType.String |
"string" |
string |
CsvFormatterType.Guid |
"guid" |
Guid |
Les enums sont également supportés sans nécessiter de constante
CsvFormatterType. Ils sont sérialisés par nom par défaut. Pour obtenir la valeur numérique, appliquer[CsvSerializerFormat(Format = "D")]sur la propriété. La désérialisation accepte le nom (insensible à la casse) ou la valeur numérique.
**Priorité 😗*
[CsvSerializerFormat]sur la propriété > formatter parFieldName> formatter global (sansFieldName).
✅ Validation
// Configuré à l'enregistrement
services.AddKapelaCsvSerializer(options =>
{
options.ValidationRules =
[
new CsvValidationRule { Index = 0, RegEx = @"^\d+$", RegexLabel = "La colonne 0 doit être numérique" },
new CsvValidationRule { Index = 1, RegEx = @"^.{1,50}$", RegexLabel = "La colonne 1 doit faire entre 1 et 50 caractères" }
];
});
// Validation
CsvValidationResult result = csv.Validate(content);
if (!result.Success)
{
foreach (var detail in result.Errors)
Console.WriteLine($"Ligne {detail.Line} : {string.Join(", ", detail.Errors.Select(e => e.Error))}");
}
➕ Ajouter des erreurs de validation personnalisées
CsvValidationResult expose une méthode AddError permettant d'enrichir le résultat avec des règles métier que le package ne peut pas gérer nativement. Si une erreur est ajoutée sur une ligne déjà présente dans le résultat, elle est regroupée avec les erreurs existantes de cette ligne.
CsvValidationResult result = csv.Validate(content);
// Enrichissement avec des règles métier
var deserialized = csv.Deserialize<Commande>(content);
foreach (var (commande, index) in deserialized.Datas.Select((x, i) => (x, i + 1)))
{
if (commande.Montant < 0)
result.AddError(line: index, message: "Le montant ne peut pas être négatif", index: 3);
}
if (!result.Success)
{
foreach (var detail in result.Errors)
Console.WriteLine($"Ligne {detail.Line} : {string.Join(", ", detail.Errors.Select(e => e.Error))}");
}
| Paramètre | Type | Description |
|---|---|---|
line |
int |
Numéro de la ligne concernée (commence à 1) |
message |
string |
Message décrivant l'erreur |
index |
int? |
Index du champ concerné (optionnel) |
🌐 Internationalisation des messages d'erreur
Les messages produits par Validate() et Deserialize() sont configurables via Options.ErrorMessages. Chaque propriété est une chaîne de format (string.Format) dont les paramètres sont décrits en détail dans l'intellisense.
services.AddKapelaCsvSerializer(options =>
{
options.ErrorMessages = new CsvErrorMessages
{
FieldCountMismatch = "Row field count ({0}) doesn't match header ({1})",
TypeMismatch = "Cannot parse '{0}' as '{1}' for property '{2}'",
RegexFailed = "Field '{0}' failed validation rule '{1}'",
UnsupportedType = "Unsupported property type '{0}'"
};
});
| Propriété | Paramètres |
|---|---|
FieldCountMismatch |
{0} nombre de champs de la ligne, {1} nombre attendu |
TypeMismatch |
{0} valeur lue, {1} type attendu, {2} nom de la propriété |
RegexFailed |
{0} nom ou index du champ, {1} libellé de la règle |
UnsupportedType |
{0} nom du type |
📜 RFC 4180 — Champs quotés
Le parsing et l'écriture CSV respectent la RFC 4180 :
- Lecture : les champs entourés de guillemets (
") sont correctement parsés, y compris s'ils contiennent le séparateur, des guillemets échappés ("") ou des retours à la ligne. - Écriture : les valeurs contenant le séparateur, un guillemet ou un retour à la ligne sont automatiquement entourées de guillemets, avec doublement des guillemets internes.
Champs multilignes
Les retours à la ligne trouvés dans un champ quoté sont remplacés par la valeur de Options.NewLineReplacement (par défaut ". ") afin de conserver la structure CsvContent (une entrée = un record).
services.AddKapelaCsvSerializer(options =>
{
options.NewLineReplacement = " - "; // Remplace \n par " - " dans les champs quotés
});
Exemple
// Lecture d'un CSV avec champs quotés
var content = csv.ImportFromString("Nom;Adresse\n\"Dupont\";\"12 rue de la Paix\nParis\"");
var result = csv.Deserialize<Client>(content);
// result.Datas.First().Adresse == "12 rue de la Paix. Paris"
// Écriture — le quoting est automatique
var list = new[] { new Client { Nom = "Du;pont", Adresse = "Paris" } };
var output = csv.Serialize(list);
// output.Content.First() contient : "Du;pont";Paris
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Kapela.Tools.Csv:
| Package | Downloads |
|---|---|
|
Kapela.Tools.Csv.OpenXmlExtensions
Ce package .NET permet d'exporter au format XLSX un contenu CSV |
GitHub repositories
This package is not used by any popular GitHub repositories.