【问题标题】:Column headers in CSV using fileHelpers library?CSV中的列标题使用fileHelpers库?
【发布时间】:2011-04-27 21:44:47
【问题描述】:

FileHelper 库中是否有内置字段属性,它将在最终生成的 CSV 中添加标题行?

我在 Google 上搜索过,但没有找到太多相关信息。目前我有这个:

DelimitedFileEngine _engine = new DelimitedFileEngine(T);
_engine.WriteStream
        (HttpContext.Current.Response.Output, dataSource, int.MaxValue);

它可以工作,但没有标题。

我正在考虑使用FieldTitleAttribute 之类的属性并将其用作列标题。

那么,我的问题是在什么时候检查属性并插入标题列?有没有人做过类似的事情?

我想插入标题并使用与实际字段名称不同的自定义文本,只需在对象的每个成员上都有一个属性:

[FieldTitleAttribute("Custom Title")]
private string Name

也许还有一个选项告诉引擎在生成标题时插入它。

所以当WriteStream或WriteString被调用时,标题行将插入自定义标题。

我为 DelimitedFileEngine 找到了几个事件,但不是检测当前记录是否是第一行以及如何在此之前插入一行的最佳方法。

【问题讨论】:

    标签: c# csv filehelpers


    【解决方案1】:

    仅包含一个更完整的示例,这将为我节省一些时间,用于 FileHelpers NuGet 包的 3.4.1 版......

    给定

    [DelimitedRecord(",")]
    public class Person
    {
       [FieldCaption("First")]
       public string FirstName { get; set; }
    
       [FieldCaption("Last")]
       public string LastName { get; set; }
    
       public int Age { get; set; }
    }
    

    以及创建它的代码

    static void Main(string[] args)
    {
        var people = new List<Person>();
        people.Add(new Person() { FirstName = "James", LastName = "Bond", Age = 38 });
        people.Add(new Person() { FirstName = "George", LastName = "Washington", Age = 43 });
        people.Add(new Person() { FirstName = "Robert", LastName = "Redford", Age = 28 });
    
        CreatePeopleFile(people);
    }
    
    private static void CreatePeopleFile(List<Person> people)
    {
        var engine = new FileHelperEngine<Person>();
    
        using (var fs = File.Create(@"c:\temp\people.csv"))
        using (var sw = new StreamWriter(fs))
        {
            engine.HeaderText = engine.GetFileHeader();
            engine.WriteStream(sw, people);
            sw.Flush();
        }
    }
    

    你明白了

    First,Last,Age
    James,Bond,38
    George,Washington,43
    Robert,Redford,28
    

    【讨论】:

      【解决方案2】:

      我知道这是一个老问题,但这里有一个适用于 v2.9.9 的答案

      FileHelperEngine<Person> engine = new FileHelperEngine<Person>();
      engine.HeaderText = engine.GetFileHeader();
      

      【讨论】:

      • 这也是他们FAQ中推荐的方法:filehelpers.net/mustread在“我想写一个带标题的文件”下
      • 这应该是选择的答案。
      • 要覆盖GetFileHeader() 生成的默认列标题,请使用[FieldCaption] 属性装饰字段。
      【解决方案3】:
      List<MyClass> myList = new List<MyClass>();
      FileHelperEngine engine = new FileHelperEngine(typeof(MyClass));
      String[] fieldNames = Array.ConvertAll<FieldInfo, String>(typeof(MyClass).GetFields(), delegate(FieldInfo fo) { return fo.Name; });
      engine.HeaderText = String.Join(";", fieldNames);
      engine.WriteFile(MapPath("MyClass.csv"), myList);
      

      【讨论】:

      • 获取字段名称的更简单的构造: var headerText = String.Join(",", typeof (MyClass).GetFields().Select(f => f.Name).ToList( )); FileHelperEngine 引擎 = 新 FileHelperEngine() { HeaderText = headerText };
      【解决方案4】:

      这里有一些代码可以做到这一点:https://gist.github.com/1391429

      要使用它,您必须使用[FieldOrder] 装饰您的字段(无论如何,这是一个很好的 FileHelpers 做法)。用法:

      [DelimitedRecord(","), IgnoreFirst(1)]
      public class Person
      {
          // Must specify FieldOrder too
          [FieldOrder(1), FieldTitle("Name")]
          string name;
      
          [FieldOrder(2), FieldTitle("Age")]
          int age;
      }
      
      ...
      
      var engine = new FileHelperEngine<Person>
      {
          HeaderText = typeof(Person).GetCsvHeader()
      };
      
      ...
      
      engine.WriteFile(@"C:\people.csv", people);
      

      但是对此的支持确实需要在 FileHelpers 本身中添加。我能想到几个设计问题,在实施之前需要回答:

      • 读取文件时会发生什么? Afaik FileHelpers 目前全部基于序号列位置并忽略列名......但如果我们现在到处都有[FieldHeader] 属性,那么我们是否也应该尝试将属性与文件中的列名匹配?如果它们不匹配,你应该抛出异常吗?如果序数位置与列名不一致会怎样?
      • 作为数据表读取时,您应该使用 A) 字段名称(当前设计),还是 B) 源文件列名称,还是 C) FieldTitle 属性?

      【讨论】:

      • 感谢您的分享和出色的工作。为了完整起见,您要添加“FieldOrderAttribute”类吗?
      • @Heinnge FieldOrderAttribute 类在 FileHelpers 2.9.9.0 库中。
      • 鉴于 FieldOrder 没有添加列标题,这如何回答这个问题?
      • 这看起来是个很酷的解决方案,但是 SourceForge 上最新的下载包是 2.0.0.0 并且它没有 FieldOrderAttribute。那个包是 2007 年的,所以 2.9.9.0 似乎永远不会正式发布。
      • 这很好用,但是在最新的代码中,他将 FieldOrderAttribute.Order 公开,因此您的 GetOrder() 代码需要从 NonPublic 稍微更改为 Public。我也不清楚你为什么要强制你的代码进入他的命名空间,但不管怎样,感谢你的解决方案,它很有魅力!
      【解决方案5】:

      我发现您可以使用 FileHelperAsyncEngine 来完成此操作。假设您的数据是“outputData”类型的名为“output”的列表,那么您可以编写如下代码:

              FileHelperAsyncEngine outEngine = new FileHelperAsyncEngine(typeof(outputData));
              outEngine.HeaderText = "Header1, Header2, Header3";
              outEngine.BeginWriteFile(outputfile);
              foreach (outputData line in output){
                  outEngine.WriteNext(line);
              }
              outEngine.Close();
      

      【讨论】:

        【解决方案6】:

        我不知道你是否还需要这个,但这是 FileHelper 的工作方式: 要包含列的标题,您需要定义一个带有标题的字符串,其分隔方式与您的文件相同。 例如使用“|”作为分隔符:

         public const string HeaderLine = @"COLUMN1|COLUMN2|COLUMN3|...";
        

        然后,当调用你的引擎时:

        DelimitedFileEngine _engine = new DelimitedFileEngine<T> { HeaderText = HeaderLine };
        

        如果您不想写标题,请不要在引擎上设置HeaderText 属性。

        【讨论】:

        • 感谢萨曼。我最终为此编写了自定义属性以及生成标题列的额外扩展方法。
        • @CDeutsc 我没有代码了。但是我创建了一个简单的 [FieldTitleAttribute("Custom Title")] 属性,禁用了内置标题,并使用自定义标题(如果有)重新创建了标题,否则使用默认字段名称。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-24
        • 1970-01-01
        相关资源
        最近更新 更多