如何使用CsvHelper将仅选择的类字段写入CSV?

14

我使用CsvHelper来读写CSV文件,它很棒,但我不知道如何只写入选定类型的字段。

假设我们有以下内容:

using CsvHelper.Configuration;

namespace Project
{
    public class DataView
    {
        [CsvField(Name = "N")]
        public string ElementId { get; private set; }

        [CsvField(Name = "Quantity")]
        public double ResultQuantity { get; private set; }

        public DataView(string id, double result)
        {
            ElementId = id;
            ResultQuantity = result;
        }
    }
}

我们希望在目前通过以下方式生成的CSV文件中,排除“数量”CsvField

using (var myStream = saveFileDialog1.OpenFile())
{
    using (var writer = new CsvWriter(new StreamWriter(myStream)))
    {
        writer.Configuration.Delimiter = '\t';
        writer.WriteHeader(typeof(ResultView));
        _researchResults.ForEach(writer.WriteRecord);
    }
}

我应该使用什么方法来动态地从CSV中排除类型字段?

如果必要的话,我们可以处理生成的文件,但我不知道如何使用 CsvHelper 删除整个CSV列。

5个回答

21

最近我需要通过确定在运行时包含哪些字段来实现类似的结果。 这是我的方法:

  1. 创建一个映射文件,通过将枚举传递到类构造函数中来映射我在运行时需要的字段

  2. public sealed class MyClassMap : CsvClassMap<MyClass>
    {
        public MyClassMap(ClassType type)
        {
            switch (type)
            {
                case ClassType.TypeOdd
                    Map(m => m.Field1);
                    Map(m => m.Field3);
                    Map(m => m.Field5);                 
                    break;
                case ClassType.TypeEven:
                    Map(m => m.Field2);
                    Map(m => m.Field4);
                    Map(m => m.Field6);                 
                    break;
                case ClassType.TypeAll:
                    Map(m => m.Field1);
                    Map(m => m.Field2);
                    Map(m => m.Field3);
                    Map(m => m.Field4);
                    Map(m => m.Field5);
                    Map(m => m.Field6);                 
                    break;
            }
        }
    }
    
  3. 使用映射配置将记录写出

    using (var memoryStream = new MemoryStream())
    using (var streamWriter = new StreamWriter(memoryStream))
    using (var csvWriter = new CsvWriter(streamWriter))
    {
        csvWriter.Configuration.RegisterClassMap(new MyClassMap(ClassType.TypeOdd));
        csvWriter.WriteRecords(records);
        streamWriter.Flush();
        return memoryStream.ToArray();
    }
    

1
这是截至2015年12月的最新正确操作方式。 - Ted

9

请将该字段标记为:

[CsvField( Ignore = true )]
public double ResultQuantity { get; private set; }

更新:算了吧,我明白你想在运行时而不是编译时执行这个操作。我将保留此条提示,以便其他可能犯同样错误的人注意。


4
在2.0版本中,CsvFieldAttribute已经被移除。 - Wallace Kelly
1
它被替换成了什么? - Scotty H
6
他们用[忽略]替换。 - ardy wongso

6
你可以这样做:
using (var myStream = saveFileDialog1.OpenFile())
{
    using (var writer = new CsvWriter(new StreamWriter(myStream)))
    {
        writer.Configuration.AttributeMapping(typeof(DataView)); // Creates the CSV property mapping
        writer.Configuration.Properties.RemoveAt(1); // Removes the property at the position 1
        writer.Configuration.Delimiter = "\t";
        writer.WriteHeader(typeof(DataView));
        _researchResults.ForEach(writer.WriteRecord);
    }
}

我们正在强制创建属性映射,然后修改它,动态删除列。

10
这是针对旧版本的CsvHelper吗?当我查看"writer.configuration"时,发现"AttributeMapping"和"Properties"不存在。请问是这样吗? - Mark Erasmus

5

我在我的代码中遇到了类似的问题,通过以下代码解决了它。

你可以这样做:

var ignoreQuantity = true;
using (var myStream = saveFileDialog1.OpenFile())
{
    using (var writer = new CsvWriter(new StreamWriter(myStream)))
    {
        var classMap = new DefaultClassMap<DataView>();
        classMap.AutoMap();
        classMap.Map(m => m.ResultQuantity).Ignore(ignoreQuantity)

        writer.Configuration.RegisterClassMap(classMap);

        writer.Configuration.Delimiter = "\t";
        writer.WriteHeader(typeof(DataView));
        _researchResults.ForEach(writer.WriteRecord);
    }
}

这是一个非常好的解决方案。只想指出,如果DataView类有子类,那么其中的每个属性也应该被设置为忽略。 - Sach

2

我也需要解决这个问题:我有几十种记录类型,它们都有一个共同的基类,以及一个必须被所有记录类型忽略的共同字段:

// Nothing special here
internal class MyClassMap<T> : ClassMap<T> where T : MyRecordBaseClass
{ 
    public MyClassMap()
    {
        AutoMap();
        Map( m => m.SOME_FIELD ).Ignore();
    }
} 

这部分通常有很好的文档,且不是动态部分。

但是有一个类需要特殊处理,需要动态忽略一个不同的字段,虽然我可以创建一个单独的映射类,但这对于我预计会有更多这样的类来说并不可扩展,所以我最终找到了正确的处理方法:

    ...
    // special processing for *one* record type
    csvwriter.Configuration.RegisterClassMap<MyClassMap<ONE_RECORD_TYPE>>();

    if (ShouldIgnore)
    {
        var map = csvwriter.Configuration.Maps.Find<ONE_RECORD_TYPE>();
        map.Map( m => m.SOME_OTHER_FIELD ).Ignore();
    }
    ...

这适用于CsvHelper版本7.1.1和12.1.1。

这非常接近我所努力实现的内容,帮了我很多,谢谢。 - renz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接