65.9K
CodeProject 正在变化。 阅读更多。
Home

Cinchoo ETL - CSV Lite Reader

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.40/5 (2投票s)

2021年12月30日

CPOL

5分钟阅读

viewsIcon

8849

.NET 的简单快速轻量级 CSV 文件读取器

1. 引言

ChoETL 是一个开源的 .NET ETL (提取、转换和加载) 框架。它是一个基于代码的库,用于从多个源提取数据、转换数据,并将数据加载到 .NET 环境中的数据仓库中。您可以快速地将数据加载到数据仓库中。本文将介绍 ChoETL 框架提供的 CSVReader 组件。这是一个简单的实用类,用于从文件/源提取 CSV 数据。

特点

  • 超快速 CSV 读取器,快速解析 CSV 文件 (100 万行,20 列,大约需要 7 秒)
  • 基于流的解析器可提供极致的性能、低资源使用率以及几乎无限的通用性,可扩展到任何大小的数据文件,甚至数十或数百 GB
  • 遵循 CSV 标准文件规则 (多行、带引号的列等)
  • 除了逗号,还可以使用大多数分隔字符,包括制表符分隔的字段。
  • 公开对象的 IEnumarable 列表 - 通常与 LINQ 查询一起用于投影、聚合和过滤等操作
  • 支持延迟读取
  • 能够从 CSV 文件获取类型化的对象列表

2. 要求

此框架库使用 C# 编写,基于 .NET 4.5 Framework / .NET Core 2.x。

3. “Hello World!” 示例

  • 打开 VS.NET 2013 或更高版本
  • 创建一个示例 VS.NET (.NET Framework 4.5) 控制台应用程序项目
  • 根据 .NET 环境,使用 Nuget 命令通过 程序包管理器控制台 安装 ChoETL
    • Install-Package ChoETL
    • Install-Package ChoETL.NETStandard
  • 使用 ChoETL 命名空间
  • 使用 ChoCSVLiteReader 类解析 CSV 文件

让我们从查看一个读取包含两列的 CSV 文件的简单示例开始。

列表 3.1 示例 CSV 数据文件 (Emp.csv)
Id,Name
1,Tom
2,Carl
3,Mark

有许多方法可以以最少的设置开始 CSV 文件解析。

3.1. 快速加载 - 数据优先方法

这是 零配置、快速加载 CSV 文件的方式。不需要 POCO 对象。下面的示例代码展示了如何加载文件。

列表 3.1.1 使用迭代器加载 CSV 文件 (最快)
using (var r = new ChoCSVLiteReader())
{
    //Open the reader, skip the header
    foreach (var cols in r.ReadFile("emp.csv").Skip(1))
    {
        Console.WriteLine($"Id: {cols[0]}");
        Console.WriteLine($"Name: {cols[1]}");
    }
}

示例 Fiddle: https://dotnetfiddle.net/kWhr27

列表 3.1.2 使用循环加载 CSV 文件 (最快)
using (var r = new ChoCSVLiteReader())
{
    //Open the reader, skip the header 
    var recNum =  r.ReadFile("emp.csv").Skip(1).GetEnumerator();
    while (recNum.MoveNext())
    {
        var cols = recNum.Current;
        Console.WriteLine($"Id: {cols[0]}");
        Console.WriteLine($"Name: {cols[1]}");
    }
}

示例 Fiddle: https://dotnetfiddle.net/bV7nq5

您也可以按名称访问 csv 字段。下面的示例展示了如何按名称访问它们。

使用 ChoDynamicObject (一种特殊的 ExpandoObject)

列表 3.1.3 使用列名加载 CSV 文件 (使用 ChoDynamicObject)
using (var r = new ChoCSVLiteReader())
{
    foreach (dynamic rec in r.ReadFile<ChoDynamicObject>("emp.csv", true))
    {
        Console.WriteLine($"Id: {rec.Id}");
        Console.WriteLine($"Name: {rec.Name}");
    }
}

示例 Fiddle: https://dotnetfiddle.net/PTnx2L

使用 ExpandoObject

列表 3.1.4 使用列名加载 CSV 文件 (使用 ExpandoObject)
using (var r = new ChoCSVLiteReader())
{
    foreach (var rec in r.ReadFile<ExpandoObject>("emp.csv", true))
    {
        Console.WriteLine($"Id: {rec.Id}");
        Console.WriteLine($"Name: {rec.Name}");
    }
}

如果 CSV 文件不带标题,CSVReader 会自动将列命名为 Column1Column2 ... 在动态对象中。

3.2. 代码优先方法

这是另一种 零配置 的方式,使用 POCO 类解析和加载 CSV 文件。首先,定义一个简单的类来匹配底层 CSV 文件布局。

清单 3.2.1 简单的 POCO 实体类
public partial class EmployeeRec
{
    public int Id { get; set; }
    public string Name { get; set; } 
}

在上面的示例中,该类定义了两个属性,与示例 CSV 文件模板匹配。

3.2.1 使用用户定义的映射器

下面的示例展示了如何使用自定义用户定义的映射器加载 CSV。

列表 3.2.1.1 使用自定义用户定义的映射器加载 CSV 文件
foreach (var rec in r.ReadFile<EmployeeRec>("emp.csv", true, 
     mapper: (lineno, cols, rec) =>
     {
         rec.Id = cols[0].CastTo<int>();
         rec.Name = cols[1];
     }))
{
    Console.WriteLine($"Id: {rec.Id}");
    Console.WriteLine($"Name: {rec.Name}");
}

在上面的示例中,我们通过映射器函数控制将 CSV 值加载到对象成员中。

示例 Fiddle: https://dotnetfiddle.net/NZZ5EK

3.2.2 使用默认内置映射器

下面的示例展示了如何使用 CSV 读取器附带的默认内置映射器加载 CSV 文件。

列表 3.2.2.1 使用内置映射器加载 CSV 文件 (默认映射)
foreach (var rec in r.ReadFile<EmployeeRec>("emp.csv", true))
{
    Console.WriteLine($"Id: {rec.Id}");
    Console.WriteLine($"Name: {rec.Name}");
}

在上面的示例中,我们让解析器使用内置映射器功能将 CSV 值加载到对象成员中。默认情况下,内置映射器通过索引将 CSV 列映射到对象成员 (第一列映射到第一个对象成员,第二列映射到第二个对象成员,依此类推)。

示例 Fiddle: https://dotnetfiddle.net/IZRKWT

3.2.3 使用位置内置映射器

如果 CSV 文件中的列顺序与定义的 POCO 模型对象不同,但想按位置映射加载它们,可以通过用 ColumnAttribute 装饰对象成员来指定 CSV 列的映射顺序。

列表 3.2.3.1 带有 OrderAttribute 的 POCO 实体类
public partial class EmployeeRec
{
    [Column(Order=1)]
    public string Name { get; set; } 
    [Column(Order=0)] 
    public int Id { get; set; }
}
列表 3.2.3.2 使用内置映射器加载 CSV 文件 (位置映射)
foreach (var rec in r.ReadFile<EmployeeRec>("emp.csv", true))
{
    Console.WriteLine($"Id: {rec.Id}");
    Console.WriteLine($"Name: {rec.Name}");
}

在上面的示例中,解析器在解析过程中使用 OrderAttribute 将 CSV 列映射到相应的对象成员。

示例 Fiddle: https://dotnetfiddle.net/fwd3j5

3.2.4 使用命名内置映射器

如果 CSV 文件中的列标题与定义的 POCO 模型对象成员不匹配,您可以使用 DisplayNameAttribute / DisplayAttribute 来指定 CSV 列名到对象成员的匹配。

列表 3.2.4 带有 DisplayNameAttribute 的 POCO 实体类
public partial class EmployeeRec
{
    [DisplayName("Id")]
    public int Identifier { get; set; }
    [DisplayName("Name")]
    public string GivenName { get; set; } 
}
列表 3.2.5 使用内置映射器加载 CSV 文件 (名称映射)
foreach (var rec in r.ReadFile<EmployeeRec>("emp.csv", true))
{
    Console.WriteLine($"Id: {rec.Id}");
    Console.WriteLine($"Name: {rec.Name}");
}

在上面的示例中,解析器在解析过程中使用显示属性将 CSV 列映射到相应的对象成员。

示例 Fiddle: https://dotnetfiddle.net/K65Ywq

3.2. 其他读取器方法

非泛型重载

  1. ReadText - 解析 csv 文本,返回 string[]
  2. ReadFile - 解析 csv 文件,返回 string[]
  3. Read - 解析 csv 流,返回 string[]
  4. ReadLines - 解析 csv 行,返回 string[]

泛型重载

  1. ReadText<T> - 解析 csv 文本,返回 T
  2. ReadFile<T> - 解析 csv 文件,返回 T
  3. Read<T> - 解析 csv 流,返回 T
  4. ReadLines<T> - 解析 csv 行,返回 T

3.3. CSV 到 DataTable

Cinchoo ETL 库提供了一个辅助方法,可以将任何可枚举对象转换为 DataTable。此转换有助于将 CSV 数据绑定到网格/其他控件/在内存中处理等。

下面的示例展示了如何将 CSV 转换为 DataTable

列表 3.3.1 将 CSV 转换为 DataTable
using (var r = new ChoCSVLiteReader())
{
    var recs = r.ReadFile<EmployeeRec>("emp.csv", true);
    var dt = recs.AsDataTable();
}

3.4. CSV 到 DataReader

Cinchoo ETL 库提供了一个辅助方法,可以将任何可枚举对象转换为 DataReader。此转换有助于通过 ADO.NET/EF 处理 (导出) 大量 CSV 文件到任何数据库。

下面的示例展示了如何将 CSV 转换为 DataReader

列表 3.4.1 将 CSV 转换为 DataReader
using (var r = new ChoCSVLiteReader())
{
    var recs = r.ReadFile<EmployeeRec>("emp.csv", true);
    var dr = recs.AsDataReader();
}

有关 Cinchoo ETL 的更多信息,请访问其他 CodeProject 文章。

历史

  • 2021 年 12 月 30 日:初始版本
© . All rights reserved.