9

最近、CSV の読み取りと書き込みを行っていて、これまでのところ素晴らしいCsvHelperに出くわしました。小さな問題が 1 つあります。ファイルを読み取るときにカスタム コンバーターを使用しますが、ファイルを書き戻すと、その形式が失われます。私のCSV形式は次のようになります。

67,1234-1,20150115,750,20150115,1340,549,549,406,0,FRG

フィールドは、 (So, 01/15/2015 7:50 AM)という20150115,750単一のフィールドにマップされます。私のクラスマップは次のようになります。DateTimeStart

public sealed class DutyMap : CsvClassMap<Duty>
{
    static readonly CultureInfo enUS = new CultureInfo("en-US");

    public DutyMap()
    {
        Map(m => m.PersonId).Index(0);
        Map(m => m.DutyName).Index(1);
        Map(m => m.Start).ConvertUsing(row => ParseDate(row.GetField<String>(2), row.GetField<String>(3)));
        Map(m => m.End).ConvertUsing(row => ParseDate(row.GetField<String>(4), row.GetField<String>(5)));
        Map(m => m.DutyTime1).Index(6);
        Map(m => m.DutyTime2).Index(7);
        Map(m => m.FlightTime).Index(8);
        Map(m => m.CreditHours).Index(9);
        Map(m => m.DutyType).Index(10);
    }

    private static DateTime ParseDate(string date, string time)
    {
        DateTime ret;

        if (time.Length < 4)
            time = new String('0', 4 - time.Length) + time;

        if (!DateTime.TryParseExact(date + time, "yyyyMMddHHmm", enUS, DateTimeStyles.None, out ret))
            throw new FormatException(String.Format("Could not parse DateTime.  Date: {0} Time: {1}", date, time));

        return ret;
    }
}

これはうまく機能し、次のようにファイル全体の解析を呼び出すことができます。

var csv = new CsvReader(sr);
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.RegisterClassMap<DutyMap>();

Data = csv.GetRecords<Duty>().ToList();

ただし、ファイルを書き込むと:

csv.WriteRecords(Data);

ファイルは次のように書き出されます。

67,7454-1,1/15/2015 7:50:00 AM,1/15/2015 1:40:00 PM,549,549,406,0,FPG

ドキュメントを見ると、書き込み時に会話関数を指定する方法がなく、読み取りのみです。これまでに見つけた唯一の解決策は、各レコードを手動で書き込むことです。

var csv = new CsvWriter(sw);
foreach (var item in Data)
{
    csv.WriteField(item.PersonId);
    csv.WriteField(item.DutyName);
    csv.WriteField(item.Start.ToString("yyyyMMdd"));
    csv.WriteField(item.Start.ToString("Hmm"));
    csv.WriteField(item.End.ToString("yyyyMMdd"));
    csv.WriteField(item.End.ToString("Hmm"));
    csv.WriteField(item.DutyTime1);
    csv.WriteField(item.DutyTime2);
    csv.WriteField(item.FlightTime);
    csv.WriteField(item.CreditHours);
    csv.WriteField(item.DutyType);

    csv.NextRecord();
}

これを行うより良い方法はありますか?ありがとう!

4

2 に答える 2

18

カスタム型コンバーター ( https://github.com/JoshClose/CsvHelper/wiki/Custom-TypeConverter ) を使用して実行できます。ConvertToStringメソッドをオーバーライドするだけです。

public class TestConverter : DefaultTypeConverter
{
    public override string ConvertToString(TypeConverterOptions options, object value)
    {
        return base.ConvertToString(options, value);
    }
}

マッピング時にコンバーターを指定します。

Map(m => m.PersonId).Index(0).TypeConverter<TestConverter>();
于 2015-08-04T19:25:47.403 に答える
0

double を往復互換形式に変換する方法を探している場合は、G17 形式を使用する以下を使用できます。

using (var writer = new StreamWriter("C:/path..."))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
    csv.Context.TypeConverterOptionsCache.AddOptions<double?>(new TypeConverterOptions 
    { 
        Formats = new string[] { "G17" } 
    });

    csv.WriteRecords(collection);
}
于 2021-07-15T00:50:01.817 に答える