J'ai un cours comme suit:
public class Test
{
public int Id {get;set;}
public string Name { get; set; }
public string CreatedDate {get;set;}
public string DueDate { get; set; }
public string ReferenceNo { get; set; }
public string Parent { get; set; }
}
et j'ai une liste d'objets de test
List<Test>testobjs=new List();
Maintenant, je voudrais le convertir en csv au format suivant:
"1, John Grisham, 9/5/2014,9/5/2014, 1356,0\n2, Stephen King, 9/3/2014,9/9/2014, 1367,0\n3, The Rainmaker, 4/9/2014,18/9/2014,1 ";
J'ai cherché "Conversion de liste en csv c #" et j'ai obtenu les solutions suivantes:
string.Join(",", list.Select(n => n.ToString()).ToArray())
Mais cela ne mettra pas le\n comme nécessaire, c'est-à-dire pour chaque objet
Y at-il un moyen plus rapide autre que la construction de chaînes pour faire cela? S'il vous plaît aider ...
Utilisez servicestack.text
Install-Package ServiceStack.Text
puis utilisez les méthodes d'extension de chaîne ToCsv(T)/FromCsv()
Exemples: https://github.com/ServiceStack/ServiceStack.Text
Mise à jour: Servicestack.Text
est maintenant gratuit également dans la v4, qui était auparavant commerciale. Plus besoin de spécifier la version! Bonne sérialisation!
Mise à jour: Utilisez ServiceStack.Text.Core
pour .NET Core.
La question de la vitesse ayant été mentionnée, mon intérêt a été porté sur les performances relatives et la rapidité avec laquelle je pouvais l'obtenir.
Je sais que StringBuilder a été exclu, mais il semblait toujours être le plus rapide, et StreamWriter a bien sûr l'avantage d'écrire sur un MemoryStream ou directement sur un fichier, ce qui le rend polyvalent.
J'ai donc réussi un test rapide.
J'ai construit une liste d'un demi-million d'objets identiques aux vôtres.
Ensuite, j'ai sérialisé avec CsvSerializer et avec deux versions compactes serrées à la main, l'une utilisant un StreamWriter vers un MemoryStream et l'autre utilisant un StringBuilder.
Le code de la main roulé a été codé pour faire face aux citations, mais rien de plus sophistiqué. Ce code était assez serré avec le minimum que je pouvais gérer pour les chaînes intermédiaires, pas de concaténation ... mais pas de production et certainement pas de points pour le style ou la flexibilité.
Mais le résultat était identique dans les trois méthodes.
Les timings étaient intéressants:
Sérialisation d'un demi-million d'objets, cinq exécutions avec chaque méthode, toujours au MS le plus proche:
StringBuilder 703 734 828 671 718 Avge= 730.8
MemoryStream 812 937 874 890 906 Avge= 883.8
CsvSerializer 1,734 1,469 1,719 1,593 1,578 Avge= 1,618.6
C'était sur un haut de gamme i7 avec beaucoup de RAM.
Toutes choses étant égales par ailleurs, j'utiliserais toujours la bibliothèque.
Mais si une différence de performances de 2: 1 devenait critique, ou si RAM ou d’autres problèmes exagéraient la différence sur un jeu de données plus volumineux, ou si les données arrivaient par fragments et étaient envoyées directement sur disque, I pourrait juste être tenté ...
Juste au cas où quiconque serait intéressé, le noyau du code (pour la version de StringBuilder) était
private void writeProperty(StringBuilder sb, string value, bool first, bool last)
{
if (! value.Contains('\"'))
{
if (!first)
sb.Append(',');
sb.Append(value);
if (last)
sb.AppendLine();
}
else
{
if (!first)
sb.Append(",\"");
else
sb.Append('\"');
sb.Append(value.Replace("\"", "\"\""));
if (last)
sb.AppendLine("\"");
else
sb.Append('\"');
}
}
private void writeItem(StringBuilder sb, Test item)
{
writeProperty(sb, item.Id.ToString(), true, false);
writeProperty(sb, item.Name, false, false);
writeProperty(sb, item.CreatedDate, false, false);
writeProperty(sb, item.DueDate, false, false);
writeProperty(sb, item.ReferenceNo, false, false);
writeProperty(sb, item.Parent, false, true);
}
Votre meilleure option serait d'utiliser une bibliothèque existante. Cela vous évite d'avoir à le trouver vous-même et vous aurez probablement à éviter des caractères spéciaux, à ajouter des lignes d'en-tête, etc. .. Vous pouvez utiliser le CSVSerializer de ServiceStack. Mais il y en a plusieurs autres dans nuget . Créer le CSV sera alors aussi simple que string csv = CsvSerializer.SerializeToCsv(testobjs);
LINQtoCSV est le plus rapide et le plus léger que j'ai trouvé et est disponible sur GitHub. Vous permet de spécifier des options via des attributs de propriété.
Vous pouvez utiliser la bibliothèque FileHelpers pour convertir la liste d'objets en csv.
Considérons l'objet donné, ajoutez l'attribut DelimitedRecord à celui-ci.
[DelimitedRecord(",")]
public class Test
{
public int Id {get;set;}
public string Name { get; set; }
public string CreatedDate {get;set;}
public string DueDate { get; set; }
public string ReferenceNo { get; set; }
public string Parent { get; set; }
}
Une fois que la liste est remplie (comme pour la question, il s'agit de testobjs)
var engine = new FileHelperEngine<Test>();
engine.HeaderText = engine.GetFileHeader();
string dirPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + ConfigurationManager.AppSettings["MyPath"];
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
//File location, where the .csv goes and gets stored.
string filePath = Path.Combine(dirPath, "MyTestFile_" + ".csv");
engine.WriteFile(filePath, testobjs);
Cela fera juste le travail pour vous. J'avais utilisé cela pour générer des rapports de données pendant un certain temps jusqu'à ce que je passe à python.
PS: Trop tard pour répondre, mais espérons que cela aidera quelqu'un.
Utilisez Cinchoo ETL
Install-Package ChoETL
ou
Install-Package ChoETL.NETStandard
Un exemple montre comment l'utiliser
List<Test> list = new List<Test>();
list.Add(new Test { Id = 1, Name = "Tom" });
list.Add(new Test { Id = 2, Name = "Mark" });
using (var w = new ChoCSVWriter<Test>(Console.Out)
.WithFirstLineHeader()
)
{
w.Write(list);
}
CSV de sortie:
Id,Name,CreatedDate,DueDate,ReferenceNo,Parent
1,Tom,,,,
2,Mark,,,,
Pour plus d'informations, allez sur github