C# CSV - 读取和写入 CSV 数据
最后修改于 2023 年 7 月 5 日
C# CSV 教程展示了如何在 C# 中读取和写入 CSV 数据。
CSV
CSV (逗号分隔值) 是一种非常流行的导入和导出数据格式,用于电子表格和数据库。CSV 文件中的每一行都是一个数据记录。每个记录由一个或多个字段组成,字段之间用逗号分隔。虽然 CSV 是一种非常简单的数据格式,但可能存在许多差异,例如不同的分隔符、换行符或引用字符。
在本文中,我们使用 CsvHelper
库读取和写入 CSV 数据。
$ dotnet add package CsvHelper
我们需要将 CsvHelper
包添加到我们的项目中。
C# CSV 按记录读取数据
在下面的示例中,我们按记录读取 CSV 文件。
FirstName,LastName,Occupation John,Doe,gardener Roger,Roe,driver Lucy,Smith,teacher
我们有这个 users.csv
文件。
using System.Globalization; using CsvHelper; using CsvHelper.Configuration; var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture) { HasHeaderRecord = false }; using var streamReader = File.OpenText("users.csv"); using var csvReader = new CsvReader(streamReader, csvConfig); string value; while (csvReader.Read()) { for (int i = 0; csvReader.TryGetField<string>(i, out value); i++) { Console.Write($"{value} "); } Console.WriteLine(); }
Read
方法将读取器推进到下一条记录。我们使用 TryGetField
读取记录的字段。
$ dotnet run FirstName LastName Occupation John Doe gardener Roger Roe driver Lucy Smith teacher
C# CSV 将数据读取到对象中
在下一个示例中,我们使用 GetRecords
将数据读取到对象中。
using System.Globalization; using CsvHelper; using var streamReader = File.OpenText("users.csv"); using var csvReader = new CsvReader(streamReader, CultureInfo.CurrentCulture); var users = csvReader.GetRecords<User>(); foreach (var user in users) { Console.WriteLine(user); } record User(string FirstName, String LastName, string Occupation);
在该示例中,我们定义了 User
类,并将 users.csv
文件的记录读取到此类的实例中。 GetRecords
返回给定类型的 IEnumerable
。
$ dotnet run User { FirstName = John, LastName = Doe, Occupation = gardener } User { FirstName = Roger, LastName = Roe, Occupation = driver } User { FirstName = Lucy, LastName = Smith, Occupation = teacher }
C# CSV 配置
在下面的示例中,我们将使用带有分号分隔符和注释的 CSV 文件。 为了解析这种不同的“CSV”文件,我们需要配置解析器。
# this is users.csv file John;Doe;gardener Roger;Roe;driver Lucy;Smith;teacher
我们有这个 users.csv
文件。
using System.Globalization; using CsvHelper; using CsvHelper.Configuration; var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture) { HasHeaderRecord = false, Comment = '#', AllowComments = true, Delimiter = ";", }; using var streamReader = File.OpenText("users.csv"); using var csvReader = new CsvReader(streamReader, csvConfig); while (csvReader.Read()) { var firstName = csvReader.GetField(0); var lastName = csvReader.GetField(1); var occupation = csvReader.GetField(2); Console.WriteLine($"{firstName} {lastName} is {occupation}"); }
使用 CsvConfiguration
配置读取器。
var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture) { HasHeaderRecord = false, Comment = '#', AllowComments = true, Delimiter = ";", };
我们告诉读取器没有标头,并且注释字符为 #。 我们允许文件中的注释并设置注释的字符。(实际上,我们不必设置注释字符,因为默认情况下使用 #。)我们将分隔符设置为分号字符。(默认情况下忽略空行。)
using var csvReader = new CsvReader(streamReader, csvConfig);
配置文件传递给 CsvReader
。
$ dotnet run John Doe is gardener Roger Roe is driver Lucy Smith is teacher
C# CSV 引用字段
在下面的示例中,我们展示了如何引用字段。
using System.Globalization; using CsvHelper; using CsvHelper.Configuration; var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture) { ShouldQuote = args => args.Row.Index == 1 }; var users = new List<User> { new (1, "John Doe", "gardener", "12/5/1997"), new (2, "Lucy Smith", "teacher", "5/12/1983"), new (3, "Roger Roe", "driver", "4/2/2001"), new (4, "Robert Smith", "cook", "21/11/1976"), new (5, "Maria Smith", "accountant", "5/9/1986"), }; using var fs = new StreamWriter("users.csv"); using var csvWriter = new CsvWriter(fs, csvConfig); csvWriter.WriteHeader<User>(); csvWriter.NextRecord(); csvWriter.WriteRecords(users); record User(int Id, string Name, string Occupation, string DateOfBirth);
我们有一个用户列表。 我们决定引用每行中的第二个字段。
var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture) { ShouldQuote = args => args.Row.Index == 1 };
在 CsvConfiguration
中,我们将 ShouldQuote
属性设置为对第二个字段返回 true。
$ dotnet run $ cat users.csv Id,"Name",Occupation,DateOfBirth 1,"John Doe",gardener,12/5/1997 2,"Lucy Smith",teacher,5/12/1983 3,"Roger Roe",driver,4/2/2001 4,"Robert Smith",cook,21/11/1976 5,"Maria Smith",accountant,5/9/1986
C# CSV WriteField
记录中的字段使用 WriteField
写入。
using System.Globalization; using System.Text; using CsvHelper; var users = new List<User> { new ("John", "Doe", "gardener"), new ("Roger", "Roe", "driver"), new ("Lucy", "Smith", "teacher"), }; using var mem = new MemoryStream(); using var writer = new StreamWriter(mem); using var csvWriter = new CsvWriter(writer, CultureInfo.CurrentCulture); csvWriter.WriteField("FirstName"); csvWriter.WriteField("LastName"); csvWriter.WriteField("Occupation"); csvWriter.NextRecord(); foreach (var user in users) { csvWriter.WriteField(user.FirstName); csvWriter.WriteField(user.LastName); csvWriter.WriteField(user.Occupation); csvWriter.NextRecord(); } writer.Flush(); var res = Encoding.UTF8.GetString(mem.ToArray()); Console.WriteLine(res); record User(string FirstName, string LastName, string Occupation);
在该示例中,我们将 CSV 数据写入内存,然后写入控制台。
csvWriter.WriteField("FirstName"); csvWriter.WriteField("LastName"); csvWriter.WriteField("Occupation"); csvWriter.NextRecord();
首先,我们写入标头。 NextRecord
方法添加一个换行符。
foreach (var user in users) { csvWriter.WriteField(user.FirstName); csvWriter.WriteField(user.LastName); csvWriter.WriteField(user.Occupation); csvWriter.NextRecord(); }
WriteField
将字段写入 CSV 文件。 使用 NextRecord
启动新记录。
writer.Flush();
要实际写入数据,我们需要调用 Flush
。
var result = Encoding.UTF8.GetString(mem.ToArray()); Console.WriteLine(result);
我们将数据从内存写入控制台。
$ dotnet run FirstName,LastName,Occupation John,Doe,gardener Roger,Roe,driver Lucy,Smith,teacher
C# CSV 使用 WriteRecords 写入数据
在下面的示例中,我们使用 WriteRecords
一次性写入所有记录。
using System.Globalization; using CsvHelper; var users = new List<User> { new ("John", "Doe", "gardener"), new ("Lucy", "Smith", "teacher"), new ("Roger", "Roe", "writer"), }; using var writer = new StreamWriter(Console.OpenStandardOutput()); using var csvWriter = new CsvWriter(writer, CultureInfo.CurrentCulture); csvWriter.WriteHeader<User>(); csvWriter.NextRecord(); // adds new line after header csvWriter.WriteRecords(users); record User(string FirstName, string LastName, string Occupation);
在该示例中,我们将用户对象列表中的数据写入控制台。 WriteHeader
从给定的成员写入标头记录。
C# CSV 自定义解决方案
通常,建议使用现有的库来处理 CSV。 尽管 CSV 看起来很简单,但提供一个强大的解决方案并不容易。(例如,字段可能被引用。)
John Doe, gardener, 12/5/1997 Jane Doe, teacher, 5/10/1983 Robert Smith, driver, 4/2/2001 Maria Smith, cook, 9/11/1976
这是 data.csv
文件。
using System.Text; var path = "data.csv"; var lines = File.ReadLines(path, Encoding.UTF8); var users = from line in lines let fields = line.Replace(", ", ",").Split(",") select new User(fields[0], fields[1], DateTime.Parse(fields[2])); var sorted = from user in users orderby user.DateOfBirth descending select user; foreach (var user in sorted) { Console.WriteLine(user); } public record User(string Name, string Occupation, DateTime DateOfBirth);
该示例使用 Linq 解析 CSV 文件。 它还按降序排列用户的生日。
$ dotnet run User { Name = Robert Smith, Occupation = driver, DateOfBirth = 4/2/2001 12:00:00 AM } User { Name = John Doe, Occupation = gardener, DateOfBirth = 12/5/1997 12:00:00 AM } User { Name = Jane Doe, Occupation = teacher, DateOfBirth = 5/10/1983 12:00:00 AM } User { Name = Maria Smith, Occupation = cook, DateOfBirth = 9/11/1976 12:00:00 AM }
C# 将 HTML 表格导出到 CSV 文件
在下一个示例中,我们从网站抓取 HTML 表格并将数据导出到 CSV 文件。
对于网络抓取,我们使用 AngleSharp 库。
using System.Globalization; using AngleSharp; using CsvHelper; var config = Configuration.Default.WithDefaultLoader(); using var context = BrowsingContext.New(config); var url = "https://nrf.com/resources/top-retailers/top-100-retailers/top-100-retailers-2020"; using var doc = await context.OpenAsync(url); var htable = doc.GetElementById("stores-list--section-23906"); var trs = htable.QuerySelectorAll("tr").Skip(1); using var fs = new StreamWriter("data.csv"); using var writer = new CsvWriter(fs, CultureInfo.CurrentCulture); var rows = new List<Row>(); foreach (var tr in trs) { var tds = tr.QuerySelectorAll("td").Take(3); var fields = (from e in tds select e.TextContent).ToArray(); var row = new Row(fields[0], fields[1], fields[2]); rows.Add(row); } writer.WriteRecords(rows); record Row(string Rank, string Company, string Sales);
我们从一个包含 2020 年美国前 100 名零售商的表格中抓取数据。
var config = Configuration.Default.WithDefaultLoader(); using var context = BrowsingContext.New(config); var url = "https://nrf.com/resources/top-retailers/top-100-retailers/top-100-retailers-2020"; using var doc = await context.OpenAsync(url);
我们设置 AngleSharp 上下文并从提供的链接检索文档。
var htable = doc.GetElementById("stores-list--section-23906"); var trs = htable.QuerySelectorAll("tr").Skip(1);
我们找到 HTML 表格并选择除标头之外的所有行。
using var fs = new StreamWriter("data.csv"); using var writer = new CsvWriter(fs, CultureInfo.CurrentCulture);
我们设置 CsvWriter
。
foreach (var tr in trs) { var tds = tr.QuerySelectorAll("td").Take(3); var fields = (from e in tds select e.TextContent).ToArray(); var row = new Row(fields[0], fields[1], fields[2]); rows.Add(row); }
我们从表格的前三列获取数据。
writer.WriteRecords(rows);
最后,记录使用 WriteRecords
写入文件。
来源
在本文中,我们使用 CsvHelper
库在 C# 中读取和写入了 CSV 数据。
作者
列出所有 C# 教程。