技术频道导航
HTML/CSS
.NET技术
IIS技术
PHP技术
Js/JQuery
Photoshop
Fireworks
服务器技术
操作系统
网站运营

赞助商

分类目录

赞助商

最新文章

搜索

C# .NET使用CsvHelper读写CSV文件,快速又易用

作者:admin    时间:2023-5-18 20:40:28    浏览:

C# .NET 解析并读写 CSV 文件,本文详细介绍如何使用 CsvHelper 来完成这个操作。

 C# .NET使用CsvHelper读写CSV文件,快速又易用

CsvHelper 介绍

CsvHelper 是一个用于读取和写入CSV文件的.NET库,非常快速、灵活且易于使用。

CsvHelper 有如下几大特征:

  • 快速
    即时编译类以获得极快的性能。
  • 灵活
    写入时保守,读取时自由。
  • 便于使用
    读取和写入就像 GetRecords<T>()WriteRecords(records) 一样简单。无需配置。
  • 高度可配置
    具有丰富的映射和属性系统,可将任何类型的 CSV 文件配置为任何类型的类。
  • 优雅的回退
    当读取非标准文件时,回退将匹配 MS Excel 解析。
  • 可在任何地方运行
    CsvHelper 建立在 .NET Standard 2.0 之上,这使得它几乎可以在任何地方运行。如果需要,可以使用旧版本的 .NET。
  • 符合RFC 4180
    遵守 RFC 4180 标准以确保跨系统的兼容性。
  • 内存使用率低
    读取记录将产生结果,因此一次只有一条记录在内存中。
  • 开源
    许多贡献者帮助使 CsvHelper 成为今天伟大的库。完全免费用于商业用途。在MS-PL和 Apache 2下获得双重许可。
  • Linux模式
    常见 Linux/SerDe 文件的模式,其中使用转义字符而不是 RFC 4180 的字段引用。
  • 字段缓存
    CSV 文件中存在重复数据时使用字段缓存的选项。这将减少内存并加快解析时间。

CsvHelper 官网:

https://joshclose.github.io/CsvHelper/

开始安装使用

下载

访问下面官方地址下载安装包。

https://www.nuget.org/packages/CsvHelper/

安装

包管理器控制台

PM> Install-Package CsvHelper

.NET CLI 控制台

> dotnet add package CsvHelper

文化资讯

CsvHelper 要求你指定要使用的 CultureInfo ,用于确定类型转换时的默认分隔符、默认行结束符和格式。你也可以更改其中任何一个配置,为你的数据选择合适的区域性。InvariantCulture在读写文件时可移植性最强,因此将在大多数示例中使用。

换行符

默认情况下,CsvHelper 将遵循RFC 4180并用\r\n编写换行符,无论你在什么操作系统上运行。CsvHelper 可以读取\r\n\r\n不进行任何配置更改。如果要以非标准格式读取或写入,可以更改NewLine

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    NewLine = Environment.NewLine,
};

读 CSV 文件

假设我们有如下所示的 CSV 文件。

Id,Name
1,one
2,two

和一个看起来像这样的类定义。

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

如果我们的类属性名称与我们的 CSV 文件头名称相匹配,我们可以在不进行任何配置的情况下读取该文件。

using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    var records = csv.GetRecords<Foo>();
}

GetRecords<T>方法将返回一个IEnumerable<T>记录,这意味着当你迭代记录时,一次只返回一条记录。这也意味着只有一小部分文件被读入内存。不过要小心。如果你执行任何执行 LINQ 投影的操作,例如调用.ToList(),整个文件将被读入内存。CsvReader是只向前的,所以如果你想对你的数据运行任何 LINQ 查询,你必须将整个文件拉入内存。

假设我们的 CSV 文件名与我们的类属性略有不同,我们不想让我们的属性匹配。

id,name
1,one
2,two

在这种情况下,名称是小写的。我们希望我们的属性名称是 Pascal 案例,这样我们就可以更改我们的属性与标题名称的匹配方式。

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    PrepareHeaderForMatch = args => args.Header.ToLower(),
};
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, config))
{
    var records = csv.GetRecords<Foo>();
}

使用配置的 PrepareHeaderForMatch,我们可以更改标头匹配的方式来匹配属性名称。标头和属性名称都在函数中运行 PrepareHeaderForMatch。当读者需要找到要为标题设置的属性时,它们现在将匹配。你可以使用此功能做其他事情,例如删除空格或其他字符。

假设 CSV 文件根本没有标题。

1,one
2,two

首先我们需要告诉读者没有头记录,使用配置。

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    HasHeaderRecord = false,
};
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, config))
{
    var records = csv.GetRecords<Foo>();
}

CsvReader 将使用属性在类中的位置作为索引位置。但是这有一个问题,你不能依赖 .NET 中类成员的顺序。我们可以通过将属性映射到 CSV 文件中的某个位置来解决这个问题。

一种方法是使用属性映射。

public class Foo
{
    [Index(0)]
    public int Id { get; set; }

    [Index(1)]
    public string Name { get; set; }
}

IndexAttribute允许你指定要将 CSV 字段用于属性的哪个位置。

你也可以按名称映射,让我们使用之前的小写标题示例,看看我们如何使用属性而不是更改标题匹配。

public class Foo
{
    [Name("id")]
    public int Id { get; set; }

    [Name("name")]
    public string Name { get; set; }
}

你还可以使用许多其他属性,请参阅如下网址。

https://joshclose.github.io/CsvHelper/examples/configuration/attributes

如果我们无法控制要映射到的类,所以我们无法向其添加属性怎么办?这种情况下,我们可以使用fluentClassMap来做映射。

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Map(m => m.Id).Name("id");
        Map(m => m.Name).Name("name");
    }
}

要使用映射,我们需要在上下文中注册它。

using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Context.RegisterClassMap<FooMap>();
    var records = csv.GetRecords<Foo>();
}

创建类映射是在 CsvHelper 中映射文件的推荐方法,因为它更强大。

你也可以手动读取行。

using (var reader = new StreamReader("path\\to\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Read();
    csv.ReadHeader();
    while (csv.Read())
    {
        var record = csv.GetRecord<Foo>();
        // Do something with the record.
    }
}

Read将向前进行,ReadHeader会将行读入 CsvHelper 作为标题值。ReadHeader分隔Read并允许你在移动到下一行之前对标题行执行其他操作。GetRecord也不会提前让阅读器允许你对你可能需要做的行做其他事情。你可能需要GetField针对单个字段或GetRecord多次调用以填充多个对象。

写 CSV 文件

现在让我们看看如何写入 CSV 文件。它基本上是同一件事,但顺序相反。

让我们使用与以前相同的类定义。

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
}

我们有一组这样的记录。

var records = new List<Foo>
{
    new Foo { Id = 1, Name = "one" },
    new Foo { Id = 2, Name = "two" },
};

我们可以将记录写入文件而无需任何配置。

using (var writer = new StreamWriter("path\\to\\file.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
    csv.WriteRecords(records);
}

WriteRecords方法会将所有记录写入文件。写入完成后,你应该调用writer.Flush()以确保写入器内部缓冲区中的所有数据都已刷新到文件中。一旦一个using块退出,writer 就会自动刷新,所以我们不必在这里明确地这样做。建议始终用using块包裹任何IDisposable对象。该对象将在using块退出后尽快处理自身(在我们的例子中也是 flush) 。

还记得我们如何不能依赖 .NET 中的属性顺序吗?如果我们正在编写一个具有标题的类,那没关系,只要我们稍后使用标题进行阅读即可。如果我们想在 CSV 文件中定位标题,我们需要指定一个索引来保证它的顺序。建议在编写时始终设置索引。

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Map(m => m.Id).Index(0).Name("id");
        Map(m => m.Name).Index(1).Name("name");
    }
}

你也可以手写行。

using (var writer = new StreamWriter("path\\to\\file.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
    csv.WriteHeader<Foo>();
    csv.NextRecord();
    foreach (var record in records)
    {
        csv.WriteRecord(record);
        csv.NextRecord();
    }
}

WriteHeader不会让你前进到下一行。 如果需要,NextRecordWriteHeader中分离允许你在标题中写入更多内容。WriteRecord也不会使你前进到下一行,从而使你能够写入多个对象或用WriteField写入单个字段。

示例

CsvHelper 读写CSV文件的示例,请参阅以下文章:

总结

本文详细介绍了 C# .NET 使用 CsvHelper 读写CSV文件的方法。CSVHelper 是在 C# 中使用 CSV 的鼻祖,它根本不需要做任何映射,它自己处理双引号、换行和枚举解析,它可以处理完全自定义的映射、自定义类型转换。此外,它的速度又快又易用,并且还是免费的可用于商用用途,真的是一个让人惊叹的库。

相关文章

标签: CSharp  asp.net  CsvHelper  CSV  
x
  • 站长推荐
/* 左侧显示文章内容目录 */