简体   繁体   English

如何在不使用 class 映射的情况下控制 CsvHelper 写入 CSV 文件头的顺序?

[英]How to control the order in which CSV file headers are written by CsvHelper without using a class a mapping?

I have the following method to write dynamic CSV file records:我有以下方法写动态CSV文件记录:

 public byte[] BuildProductsFile(List<object> records)
    {
      var firstRow = records.FirstOrDefault();
      var columnHeaders = ((IDictionary<string, object>) firstRow).Keys.ToList();

      using var memoryStream = new MemoryStream();
      using (var streamWriter = new StreamWriter(memoryStream))
      {
        using var csvWriter = new CsvWriter(streamWriter);
        csvWriter.WriteRecords(records);

      }
      return memoryStream.ToArray();
    }

When I do WriteRecords, it changes header names to alphabetic order which I don't want since afterwards my rows correspond to incorrect headers.当我执行 WriteRecords 时,它会将 header 名称更改为我不想要的字母顺序,因为之后我的行对应于不正确的标题。 I can't use a class to specify header names because they will be different depending on different tables which user would like to get.我不能使用 class 来指定 header 名称,因为它们会根据用户想要获得的不同表而有所不同。

My question is can I write the header names in the correct sequence, which I can get from我的问题是我可以按正确的顺序编写 header 名称吗,我可以从中得到

var columnHeaders = ((IDictionary<string, object>) firstRow).Keys.ToList();

Alternatively, is there a way to disable alphabetical order header placing?或者,有没有办法禁用字母顺序 header 放置?

You must be using a version of CsvHelper between 10.0.0 and 12.0.0 .您必须使用10.0.012.0.0之间的CsvHelper版本。 Between these two versions, CsvWriter.WriteRecords() would write ExpandoObject properties in alphabetical order.在这两个版本之间, CsvWriter.WriteRecords()将按字母顺序写入ExpandoObject属性。 Upgrade to a later version (or downgrade to an earlier version) to eliminate this behavior.升级到更高版本(或降级到更早版本)以消除此行为。

For confirmation, see the change log :如需确认,请参阅更改日志

10.0.0 10.0.0

Features:特征:

  • Write ExpandoObject and IDynamicMetaObjectProvider object properties in ascending order to ensure order of property creation doesn't matter.按升序编写 ExpandoObject 和 IDynamicMetaObjectProvider object 属性,以确保属性创建顺序无关紧要。

12.0.0 12.0.0

Features特征

  • Added config option for sorting dynamic object properties when writing.添加了用于在写入时对动态 object 属性进行排序的配置选项。 Defaults to property value set order.默认为属性值设置顺序。

Breaking Changes重大变化

  • Added IComparer<string> IWriterConfiguration.DynamicPropertySort .添加IComparer<string> IWriterConfiguration.DynamicPropertySort
  • Added IComparer<string> Configuration.DynamicPropertySort .添加IComparer<string> Configuration.DynamicPropertySort

See When writing dynamic object order of property assignments is significant #1037 for a discussion of why this happened.请参阅When writing dynamic object order of property assignment is Significant #1037讨论为什么会发生这种情况。

A demo of CsvHelper failing in version 11 can be found here: demo #1 .可以在此处找到版本 11 中失败的CsvHelper演示:演示 #1

A demo of CsvHelper working as desired in the most recent version, version 26, can be found here: demo #2 .可以在此处找到在最新版本 26 中按需要工作的CsvHelper演示:演示 #2

And if you really need to write your CSV columns in an order specified by a sequence of strings, you can use CsvConfiguration.DynamicPropertySort mentioned above:如果您确实需要按照字符串序列指定的顺序编写 CSV 列,则可以使用上面提到的CsvConfiguration.DynamicPropertySort

class OrderComparer : IComparer<string>
{
    // Note this comparer assumes that all strings to be compared are present in the incoming collection of strings, and will throw an exception if not.
    // If this is not desired, enhance as required.
    readonly Dictionary<string, int> orders;
    public OrderComparer(IEnumerable<string> orderedHeaders) => orders = orderedHeaders.Select((i, s) => (i, s)).ToDictionary(p => p.i, p => p.s);
    public int Compare(string x, string y) =>  orders[x] - orders[y];
}

public static  byte[] BuildProductsFile(List<object> records, IEnumerable<string> orderedHeaders) =>
    BuildProductsFile(records, new OrderComparer(orderedHeaders));

public static  byte[] BuildProductsFile(List<object> records, IComparer<string> dynamicPropertySort)
{
    using var memoryStream = new MemoryStream();
    using (var streamWriter = new StreamWriter(memoryStream))
    {
        var config = new CsvConfiguration(CultureInfo.InvariantCulture)
        {
            DynamicPropertySort = dynamicPropertySort,
        };
        using var csvWriter = new CsvWriter(streamWriter, config); 
        csvWriter.WriteRecords(records);

    }
    return memoryStream.ToArray();  
}

Demo of DynamicPropertySort here: demo #3 . DynamicPropertySort的演示在这里:演示 #3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM