Architect's Log

I'm a Cloud Architect. I'm highly motivated to reduce toils with driving DevOps.

【.NET】BogusとCsvHelperでダミーデータのCSVを生成する

BogusとCsvHelperでダミーデータのCSVを生成してみました。

Bogus

Bogusは、ダミーデータを生成するライブラリです。

github.com

CsvHelper

CsvHelperは、CSVを読み書きするライブラリです。

https://joshclose.github.io/CsvHelper/

インストール

NuGetでBogusとCsvHelperをインストールします。

ソースコード

説明するより、ソースをみてもらった方が早いと思います。DumpUtil.ImageはLINQPadで使えるメソッドです。

// using Bogus;
// using Bogus.DataSets;
// using CsvHelper;

void Main() {
    // データ生成ルール
    var faker = new Faker<User>("ja")    // 日本語
        .RuleFor(u => u.ID, f => f.IndexFaker + 1)
        .RuleFor(u => u.Gender, f => f.PickRandom<Name.Gender>())
        .RuleFor(u => u.FirstName, f => f.Name.FirstName())
        .RuleFor(u => u.LastName, f => f.Name.LastName())
        .RuleFor(u => u.FullName, (f, u) => $"{u.LastName} {u.FirstName}")
        .RuleFor(u => u.Email, f => f.Person.Email)
        .RuleFor(u => u.Age, f => f.Random.Number(18, 60))
        .RuleFor(u => u.AvatarUrl, f => f.Internet.Avatar())
        .RuleFor(u => u.DateOfBirth, f => f.Person.DateOfBirth)
        .RuleFor(u => u.Phone, f => f.Person.Phone)
        .RuleFor(u => u.Created, f => f.Date.Past())
        .RuleFor(u => u.AndroidPushID, f => f.System.AndroidId());

    // 生成
    var fakes = faker.Generate(3);

    // 可視化
    fakes.Dump("CSVデータ");
    fakes.ForEach(f => Util.Image(f.AvatarUrl).Dump("アバター画像"));

    // CSV出力
    using (var writer = File.CreateText(@"d:\users.csv")) {
        var csv = new CsvWriter(writer);
        csv.Configuration.HasHeaderRecord = true;
        csv.WriteRecords(fakes);
    }
}

public class User {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName { get; set; }
    public Name.Gender Gender { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
    public string AvatarUrl { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Phone { get; set; }
    public DateTime Created { get; set; }
    public string AndroidPushID { get; set; }
}

出力データ

Dumpした結果です。それらしいデータが出力されています。

f:id:JHashimoto:20180710134715p:plain

CSV

出力されたCSVです。

ID,FirstName,LastName,FullName,Gender,Email,Age,AvatarUrl,DateOfBirth,Phone,Created,AndroidPushID
1,美咲,松本,松本 美咲,Male,Richard_40@yahoo.com,53,https://s3.amazonaws.com/uifaces/faces/twitter/nwdsha/128.jpg,1953/12/25 10:38:26,025-178-5701,2018/03/27 14:01:50,APA914SBIu3jYZflU9cfav8FGs-bXmrh5CYVIbmQ22_X3w5qnVzS7GRJzbQS6HGn3Pen0lEIQoc7veBanAQ1OA9sMgnxnvKnoFThjLq1hS2LtKelCGvzTEAwFOCM-7mlGRLSmlTE9ONXyq-221XI0awM5oDx8F38xJ5E-o_hPTp4SE-fPAKZcFl
2,陸斗,清水,清水 陸斗,Male,Shawna_42@yahoo.com,45,https://s3.amazonaws.com/uifaces/faces/twitter/anasnakawa/128.jpg,1994/12/30 8:28:39,006-917-4843,2017/12/08 23:26:56,APA91FJzrK46317uNW4Hhguh5U9p8eWpTlrePtjIwGLbpp0WsiqORr2mTpQJwlqcQIfLCVGlEpbCwiUJTgZSQ7Atj5mrEBcbgyoJahkyD49sgsRCw7RhoAoI7OtxAgJ2b0nZVbyDXrgM-7cSgLWwLYPIaHBpQP-oo6hg5TIlBflYkEK0BChQmcj
3,大和,山口,山口 大和,Male,Cindy_@gmail.com,32,https://s3.amazonaws.com/uifaces/faces/twitter/d33pthought/128.jpg,1950/11/05 16:54:33,03-0595-6835,2017/12/03 14:13:06,APA91jRe3RVnlBSv4rnXk6pbqGphV1pJ8PcI5UCeD1PlKuAbWOKc-nZaFa9YVBk2scfxoaqbR9lik4uY6cn7jcKNS22XLGk1KMUyf2PMpyoR2ISBIeRIfcLgutHm8vtbRjzzbYJ4qCLMRVL9ctfxQDPx1E3NnuEV5b_L8jpMwNjEu-rBKx9HgXo

大量データを出力する場合

プログラムでCSVを出力する方法は、特に大量データが必要なときに威力を発揮しますが、OutOfMemoryExceptionが発生しないように気を付ける必要があります。

Faker<T>.Generateは、List<T>を返すので、大量データを出力する場合は、CSV出力を分割します。

// using Bogus;
// using Bogus.DataSets;
// using CsvHelper;

void Main() {
    // データ生成ルール
    var faker = new Faker<User>("ja")    // 日本語
        .RuleFor(u => u.ID, f => f.IndexFaker + 1)
        .RuleFor(u => u.Gender, f => f.PickRandom<Name.Gender>())
        .RuleFor(u => u.FirstName, f => f.Name.FirstName())
        .RuleFor(u => u.LastName, f => f.Name.LastName())
        .RuleFor(u => u.FullName, (f, u) => $"{u.LastName} {u.FirstName}")
        .RuleFor(u => u.Email, f => f.Person.Email)
        .RuleFor(u => u.Age, f => f.Random.Number(18, 60))
        .RuleFor(u => u.AvatarUrl, f => f.Internet.Avatar())
        .RuleFor(u => u.DateOfBirth, f => f.Person.DateOfBirth)
        .RuleFor(u => u.Phone, f => f.Person.Phone)
        .RuleFor(u => u.Created, f => f.Date.Past())
        .RuleFor(u => u.AndroidPushID, f => f.System.AndroidId());

    // 100万行ずつに分ける
    using (var writer = File.CreateText(@"d:\manyusers.csv")) {
        var csv = new CsvWriter(writer);
        foreach (var i in Enumerable.Range(1, 10)) {
            csv.WriteRecords(faker.Generate(1000000));
        }
    }
}

もしくは、IEnumerable<T>を返すGenerateForeverを使ってもOKです。