web-dev-qa-db-fra.com

Moyen le plus rapide de convertir une liste d'objets en CSV avec chaque valeur d'objet dans une nouvelle ligne

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 ...

17

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.Corepour .NET Core.

28
unreal

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);
    }
12
PolicyWatcher

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);

4
AVee

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é.

0
maeneak

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.

0
kaarthick raman

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 

https://github.com/Cinchoo/ChoETL

0
RajN