管理包-CSVHelper

CsvHelper文档-5配置

CsvHelper库被设计成快速且简单易用,但是有时候默认的是设置不符合要求,需要你自己改变一些东西。所以csvHelper内置了很多自定义设置选项来改变读写行为。特别是对操作一些非标准文档的时候非常有用。

恶意注入保护

来自逗号分割的脆弱性

很多现代的Web应用程序和框架提供了电子表格导出功能,允许用户下载数据到csv或者xls文档中并用Excel或者OpenOffice Calc来打开。电子表格的单元格里经常会包含不受信任的源,比如survey_response,transaction details 和用户应用地址。这潜在会有一些危险;因为任何单元格如果以=开始的话,都是被单元格当成一个公式。

另外一个好的文章The Absurdly Underestimated Dangers of CSV Injection

注入净化

净化字段可以防止恶意注入,当在外部程序当中使用csv文件的时候,一个字段当中的公式是能够被运行的,所以可能会带来脆弱。鉴于此,如果一个字段是以=,@,+或者-开始的,那么这个字段将会被加上\t后缀,如果一个字段被引用了,那么这个字段将在引号后面加上\t,净化覆盖了MS Excel,Google Sheets和OpenOffice Calc。

  1.  
    // Turn off sanitization.
  2.  
    csv.Configuration.SanitizeForInjection = false;

注入字符

这些字符会导致净化的发生

  1.  
    // Default.
  2.  
    csv.Configuration.InjectionCharacters = new [] { '=', '@', '+', '-' };

避开注入字符

下面这个字符将用来避开注入;

  1.  
    // Default.
  2.  
    csv.Configuration.InjectionEscapeCharacter = '\t';

Headers

HasHeaderRecord

默认情况下,CsvHelper会认为文件有一个header记录,如果你的文件不包含一个header记录,那么你可以把这个选项关闭。

csv.Configuration.HasHeaderRecord = false;

HeaderValidationCallback

当Header验证运行检查运行的时候,函数会被调用。默认的函数会在没有header用来匹配给定成员验证的时候,抛出一个ValidationException异常。

  1.  
    // Turn off header validation.
  2.  
    csv.Configuration.HeaderValidationCallback = null;
  3.  
     
  4.  
    // Log instead of throwing an exception.
  5.  
    csv.Configuration.HeaderValidationCallback = ( isValid, headerNames, headerNameIndex, context ) =>
  6.  
    {
  7.  
    if( !isValid )
  8.  
    {
  9.  
    logger.WriteLine( $"Header matching ['{string.Join( "', '", headerNames )}'] names at index {headerNameIndex} was not found." );
  10.  
    }
  11.  
    };

PrepareHeaderForMatch

准备一个header字段来匹配一个成员名称,header字段和成员名称都通过这个函数来运行。你可以裁剪,移除空格,移除下划线,进行大小写转换等。

  1.  
    // Trim
  2.  
    csv.Configuration.PrepareHeaderForMatch = header => header?.Trim();
  3.  
     
  4.  
    // Remove whitespace
  5.  
    csv.Configuration.PrepareHeaderForMatch = header => header.Replace( " ", string.Empty );
  6.  
     
  7.  
    // Remove underscores
  8.  
    csv.Configuration.PrepareHeaderForMatch = header => header.Replace( "_", string.Empty );
  9.  
     
  10.  
    // Ignore case
  11.  
    csv.Configuration.PrepareHeaderForMatch = header => header.ToLower();

映射

配置类型映射

RegisterClassMap

添加一个类型映射文件后,可以在注册多个映射文件。如果你为同样的类型注册了多个映射,生效的会是最新的那个。

  1.  
    // Creates and adds a map for the given class map type TMap.
  2.  
    csv.Configuration.RegisterClassMap<TMap>();
  3.  
     
  4.  
    // Creates and adds a map for the given class map type
  5.  
    csv.Configuration.RegisterClassMap( classMapType );
  6.  
     
  7.  
    // Adds the given class map.
  8.  
    csv.Configuration.RegisterClassMap( classMap );

UnregisterClassMap

移除一个类型映射文件;

  1.  
    // Removes the class map for the given class map type.
  2.  
    csv.Configuration.UnregisterClassMap<TMap>();
  3.  
     
  4.  
    // Removes the class map for the given class map type.
  5.  
    csv.Configuration.UnregisterClassMap( Type classMapType );
  6.  
     
  7.  
    // Removes all class maps.
  8.  
    csv.Configuration.UnregisterClassMap();

Maps

设置映射, ClassMapCollection类型拥有一些方法能够帮助管理类型映射。

  1.  
    // Finds the `ClassMap` for the given record type `TRecord`.
  2.  
    var map = csv.Maps.Find<TRecord>();
  3.  
     
  4.  
    // Finds the `ClassMap` for the given type.
  5.  
    var map = csv.Maps[recordType];

AutoMap

自动使用默认的设置创建类型映射。

  1.  
    // Creates a ClassMap for given record type `TRecord`.
  2.  
    var map = csv.Configuration.AutoMap<TRecord>();
  3.  
     
  4.  
    // Creates a ClassMap for the given type.
  5.  
    var map = csv.Configuration.AutoMap( recordType );

MemberTypes

指定自动映射的时候的成员映射类型

  1.  
    // Default.
  2.  
    csv.Configuration.MemberTypes = MemberTypes.Properties;
  3.  
     
  4.  
    // Fields.
  5.  
    csv.Configuration.MemberTypes = MemberTypes.Fields;
  6.  
     
  7.  
    // Both;
  8.  
    csv.Configuration.MemberTypes = MemberTypes.Properties | MemberTypes.Fields;

IncludePrivateMembers

自动映射的时候包含私有成员。这个设置只能用于写入,读取则需要使用构造函数映射。

  1.  
    // Turn on.
  2.  
    csv.Configuration.IncludePrivateMembers = true;
  3.  
    IgnoreReferences
  4.  
    Ignores reference members when auto mapping. Default is false.
  5.  
     
  6.  
    // Ignore reference members.
  7.  
    csv.Configuration.IgnoreReferences = true;

PrefixReferenceHeaders

将父类成员名称用作子类header的成员的前缀

  1.  
    // Turn on.
  2.  
    csv.Configuration.PrefixReferenceHeaders = true;

Constructor Mapping

如果你希望通过构造函数的参数来创建csv文件的字段,那么你应该使用这个选项。

ShouldUseConstructorParameters

Function to determine if constructor parameters should be used to create the class instead of the default constructor and member initialization.
设定是否用带有参数的构造函数来代替默认的构造函数和成员初始化去生成类。

  1.  
    // Default
  2.  
    csv.Configuration.ShouldUseConstructorParameters = type =>
  3.  
    !type.HasParameterlessConstructor()
  4.  
    && type.HasConstructor()
  5.  
    && !type.IsUserDefinedStruct()
  6.  
    && !type.IsInterface
  7.  
    && Type.GetTypeCode( type ) == TypeCode.Object;
  8.  
     
  9.  
    // Always use constructor parameters.
  10.  
    csv.Configuration.ShouldUseConstructorParameters = type => true;
  11.  
     
  12.  
    // Never use constructor parameters.
  13.  
    csv.Configuration.ShouldUseConstructorParameters = type => false;

GetConstructor

设置用于选择映射函数构造函数,默认选择参数最多的那个。

  1.  
    // Default
  2.  
    csv.Configuration.GetConstructor = type => type.GetConstructors().OrderByDescending( c => c.GetParameters().Length ).First();

Error Handling

当错误发生的时候,你可以改变行为来做一些事情而不是抛出异常,比如忽略错误或者记入日志。

BadDataFound

一个字段包含有问题的数据是指包含引号并且这个字段没有被避开。当这样的字段数据被发现的时候,调用的函数。

  1.  
    // Ignore bad data.
  2.  
    csv.Configuration.BadDataFound = null;
  3.  
     
  4.  
    // Log bad data.
  5.  
    csv.Configuration.BadDataFound = context =>
  6.  
    {
  7.  
    logger.WriteLine( $"Bad data found on row '{context.RawRow}'" );
  8.  
    };

MissingFieldFound

当一个Missing字段被发现的时候调用的函数,默认是抛出一个MissingFieldException异常。

  1.  
    // Ignore missing field.
  2.  
    csv.Configuration.MissingFieldFound = null;
  3.  
     
  4.  
    // Log missing field.
  5.  
    csv.Configuration.MissingFieldFound = ( headerNames, index, context ) =>
  6.  
    {
  7.  
    logger.WriteLine( $"Field with names ['{string.Join( "', '", headerNames )}'] at index '{index}' was not found. );
  8.  
    };

ReadingExceptionOccurred

当读取错误发生的时候调用的函数,默认的函数会再次抛出一个给定的异常。

  1.  
    // Ignore reading exception.
  2.  
    csv.Configuration.ReadingExceptionOccurred = null;
  3.  
     
  4.  
    // Log reading exception.
  5.  
    csv.Configuration.ReadingExceptionOccurred = exception =>
  6.  
    {
  7.  
    logger.WriteLine( $"Reading exception: {exception.Message}" );
  8.  
    };

类型转换

TypeConverterCache

管理类型转换器,你可以添加,移除,或者某个类型的类型转换器。

  1.  
    // Add converter for a type.
  2.  
    csv.Configuration.TypeConverterCache.AddConverter<MyClass>( converter );
  3.  
    csv.Configuration.TypeConverterCache.AddConverter( typeof( MyClass ), converter );
  4.  
     
  5.  
    // Remove converter.
  6.  
    csv.Configuration.TypeConverterCache.RemoveConverter<MyClass>();
  7.  
    csv.Configuration.TypeConverterCache.RemoveConverter( typeof( MyClass ) );
  8.  
     
  9.  
    // Get existing converter.
  10.  
    csv.Configuration.TypeConverterCache.GetConverter<MyClass>();
  11.  
    csv.Configuration.TypeConverterCache.GetConverter( typeof( MyClass ) );

TypeConverterOptionsCache

管理TypeConverterOptions,可以添加,移除,或者一个类型的选项。

  1.  
    // Add options for a type.
  2.  
    csv.Configuration.TypeConverterOptionsCache.AddOptions<MyClass>( options );
  3.  
    csv.Configuration.TypeConverterOptionsCache.AddOptions( typeof( MyClass ), options );
  4.  
     
  5.  
    // Remove options.
  6.  
    csv.Configuration.TypeConverterOptionsCache.RemoveOptions<MyClass>();
  7.  
    csv.Configuration.TypeConverterOptionsCache.RemoveOptions( typeof( MyClass ) );
  8.  
     
  9.  
    // Get existing options.
  10.  
    csv.Configuration.TypeConverterOptionsCache.GetOptions<string>().CultureInfo = CultureInfo.CurrentCulture;
  11.  
    csv.Configuration.TypeConverterOptionsCache.GetOptions( typeof( string )).CultureInfo = CultureInfo.CurrentCulture;

读取

DetectColumnCountChanges

如果在检测到不同行的列数不一样,就会抛出一个BadDataException异常,默认这个设置是false。

  1.  
    // Turn on.
  2.  
    csv.Configuration.DetectColumnCountChanges = true;

ShouldSkipRecord

当一个记录应该被跳过的时候,函数会被调用,默认返回false;

  1.  
    // Skip if all fields are empty.
  2.  
    csv.Configuration.ShouldSkipRecord = record =>
  3.  
    {
  4.  
    return record.All( string.IsNullOrEmpty );
  5.  
    };

IgnoreBlankLines

读取的时候忽略空行,空行就是没有字符的行,这个设置默认是打开着。

  1.  
    // Turn off.
  2.  
    csv.Configuration.IgnoreBlankLines = true;
  3.  
     
  4.  
    // A,B,C // Header.
  5.  
    // // When on, this row is skipped. When off, it will be just like the next row.
  6.  
    // ,, // Not ignored. All fields are empty.

转换

TrimOptions

设置修剪字段,TrimOptions.Trim就是把字段两边的空格去掉。TrimOptions.InsideQuotes 就是把引号内的空格也去掉。

  1.  
    csv.Configuration.TrimOptions = TrimOptions.Trim;
  2.  
    ` field ` -> `field`
  3.  
    ` " field " ` -> `" field "`
  4.  
     
  5.  
    csv.Configuration.TrimOptions = TrimOptions.InsideQuotes;
  6.  
    ` field ` -> ` field `
  7.  
    ` " field " ` -> ` "field" `
  8.  
     
  9.  
    csv.Configuration.TrimOptions = TrimOptions.Trim | TrimOptions.InsideQuotes;
  10.  
    ` " field " ` -> "field"

AllowComments

允许读取的时候注释,如果设置为开,每一行会以一个注释字符开始的会被认为是注释输出行,如果设置关,那么就是普通字段,默认是关。

  1.  
    // Turn on.
  2.  
    csv.Configuration.AllowComments = true;
  3.  
    BufferSize
  4.  
    The size of the buffer used when reading. Default is 2048;
  5.  
     
  6.  
    // Double the buffer size.
  7.  
    csv.Configuration.BufferSize = csv.Configuration.BufferSize * 2;

CountBytes

转换的时候记录字节数,默认是false,这个操作会减慢转换,因为它需要获取每个字符按照特定编码的字节数。 要设置Configuration.Encoding确保准确。

  1.  
    // Turn on.
  2.  
    csv.Configuration.CountBytes = true;
  3.  
     
  4.  
    // Get count.
  5.  
    var byteCount = csv.Context.BytePosition;

Encoding

设置记录字节数的编码

  1.  
    // Change to whatever the CSV file was encoded in.
  2.  
    csv.Configuration.Encoding = Encoding.Unicode;

Writing

QuoteAllFields

写入的时候引号所有的字段,忽略其他设定。QuoteAllFields 和 QuoteNoFields不能同时打开,只能使用一个。

  1.  
    // Turn on.
  2.  
    csv.Configuration.QuoteAllFields = true;

QuoteNoFields

写入的时候不适用引号,忽略其他设定。QuoteAllFields 和 QuoteNoFields不能同时打开,只能使用一个。

  1.  
    // Turn on.
  2.  
    csv.Configuration.QuoteNoFields = true;

UseNewObjectForNullReferenceMembers

Specifies if a new object should be created and used when a reference is null. If true, a new object is created and will have default values that are written. If false, all the fields will be empty. Default is true.
设定是否在引用为null的时候创建一个新对象。true,新的对象会被创建,会写入默认值。false,所有的字段为空,默认是true。

  1.  
    public class A
  2.  
    {
  3.  
    public int AId { get; set;}
  4.  
    public B B { get; set; }
  5.  
    }
  6.  
     
  7.  
    public class B
  8.  
    {
  9.  
    public int BId { get; set; }
  10.  
    }
  11.  
     
  12.  
    var list = new List<A>
  13.  
    {
  14.  
    new A { AId = 1 }
  15.  
    };
  16.  
     
  17.  
    // Default.
  18.  
    csv.Configuration.UseNewObjectForNullReferenceMembers = true;
  19.  
    csv.WriteRecords( list );
  20.  
     
  21.  
    // Output:
  22.  
    // AId,BId
  23.  
    // 1,0
  24.  
     
  25.  
    // Turn off.
  26.  
    csv.Configuration.UseNewObjectForNullReferenceMembers = false;
  27.  
    csv.WriteRecords( list );
  28.  
     
  29.  
    // Output:
  30.  
    // AId,BId
  31.  
    // 1,

Formatting

Delimiter

分割字段的符号,默认是逗号

  1.  
    // Default.
  2.  
    csv.Configuration.Delimiter = ",";

Quote

默认的引号

  1.  
    // Default.
  2.  
    csv.Configuration.Quote = '"';

Comment

用来去除已经被注释的行的符号

    1.  
      // Default.
    2.  
      csv.Configuration.Comment = '#';
       
       
       
      实际使用,读取接口传过来的csv文件数据
       
      using CsvHelper.Configuration.Attributes;
      using System;
      using System.Collections.Generic;
      using System.Text;
      
      namespace Autobio.UDI.Common
      {
          public class PutOrganizationCsvRecord
          {
              //[Index(0)]
              //public string FOrgID { get; set; }
              //[Index(1)]
              //public string FDocumentStatus { get; set; }
          }
      }
      
      
              public JsonResult<JsonRowOData> Organizations()
              {
                  var data = GetCsvOrganizationData();
                  var currentLine = string.Empty;
                  var organizationList = new List<PutOrganizationCsvRecord>();
                  try
                  {
                      string responseText = data.Result.ToString();
                      if (responseText != "[]")//有数据进行解析循环
                      {
                          IList<string> lineStrCount = responseText.AsSpan().Slice(2, responseText.Length - 4).ToString().Split("],[", StringSplitOptions.RemoveEmptyEntries);
                          foreach (var line in lineStrCount)
                          {
                              currentLine = line.Replace("null", "");
                              using (var reader = new CsvReader(new StringReader(currentLine), CultureInfo.InvariantCulture))
                              {
                                  reader.Configuration.HasHeaderRecord = false;
                                  if (reader.Read())
                                  {
                                      var record = reader.GetRecord<PutOrganizationCsvRecord>();
                                      organizationList.Add(record);
                                  }
                              }
                          } //结束foreach
                      }
                  }
                  catch (Exception ex)
                  {
                      return new JsonResult<JsonRowOData> { code = -1, msg = "执行期间发生异常!" + ex.Message, data = null };
                      //throw ex;
                  }
                  var totalAll = organizationList.Count; //所有的
                  return JsonHelper.GetORowsResults(organizationList, totalAll);
              }
      

        

posted @ 2021-02-09 13:13  suqq小白  阅读(347)  评论(0编辑  收藏  举报