【问题标题】:Parsing CSV file into Dictionary C#将 CSV 文件解析为字典 C#
【发布时间】:2022-01-13 15:56:28
【问题描述】:

我希望将 csv 文件的内容放入字典中:

public IDictionary<string, string> allContracts = new Dictionary<string, string>();

我想知道如何做到这一点,因为我试图找到使用 csv 解析器的方法,但找不到有效的方法。我希望代码在其中运行:

public void CheckAvailability()
    {
       //this runs following a click even in a different section of my code

    }

以下是我要处理的 csv 文件中的一些示例数据:

Vehicle ID,Customer ID,Booked Date,Booked_date_week_number,Number of Days Booked,BookingStatus
    135,CU1,1-Jul-19,27,0,Booked
    71,CU2,1-Jul-19,27,0,Booked
    73,CU3,1-Jul-19,27,0,Booked
    93,CU4,1-Jul-19,27,0,Booked
    137,CU5,1-Jul-19,27,0,Booked
    24,CU6,1-Jul-19,27,0,Booked

如您所见,列名也包含在 csv 文件中,这不是问题,实际上是我正在创建的程序的基础。

另外请注意,我认为我需要使用 csv 解析器,因为正在使用的文件比这里显示的要大,所以我不想遇到内存问题。

【问题讨论】:

  • 您需要在字典中准确包含 what 您想要的内容。您想使用哪个字段作为键?你想用哪个(s)作为价值?
  • 一般来说,CSV 数据可能比您的样本更复杂。例如,如果 CSV 的单元格包含逗号,则必须引用该单元格。如果您在引用的单元格中有引号,则必须通过加倍来转义该引号。示例:“John”“Smitty”“Smith, Jr”。出于这个原因,我建议使用库来解析您的数据,例如流行的 CsvHelper。使用网站上的优秀示例非常简单。
  • 一些事情。 1)CSV文件的大小与使用CSV解析器无关,更多与文件实际有多大以及解析后是否可以直接保存在内存中有关。如果它可以放入内存中,那么您将面临更多的复杂性。 2)为什么要使用字典,是电子表格中的列之一,预计将成为关键,直接查找性能至关重要。
  • @EricJ。我将查看 CsvHelper 并使用库。感谢您抽出宝贵时间发表评论
  • 推荐使用 CSV 解析器。目前尚不清楚您为什么需要Dictionary&lt;string, string&gt;... csv 文件似乎有六 (6) 个字段。您是否有某些原因不简单地创建一个类,其中 csv 文件中的每个字段都是该类的属性?根据您选择的 CSV 阅读器,这个类可能会简化一些事情。

标签: c# csv


【解决方案1】:

我会以不同的方式处理这个问题,通过创建一个代表每一行的类,并在需要时从中创建一个字典

void Main()
{
    // See https://joshclose.github.io/CsvHelper/
    using (var reader = new StreamReader(@"C:\Temp\Bookings.csv"))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        var records = csv.GetRecords<Booking>();
        var dictionary = records.ToDictionary(r => r.VehicleID, r => r);    
    }
}

public enum BookingStatus
{
    Booked,
    // TOOD: Add other statuses
}
public class Booking
{
    [Name("Vehicle ID")]
    public int VehicleID { get; set; }
    [Name("Customer ID")]
    public string CustomerID { get; set; }
    [Name("Booked Date")]
    public DateTime BookedDate { get; set; }
    [Name("Booked_date_week_number")]
    public int BookedDateWeekNumber { get; set; }
    [Name("Number of Days Booked")]
    public int NumberOfDaysBooked { get; set; }
    [Name("BookingStatus")]
    public BookingStatus BookingStatus { get; set; }
}

请注意,如果同一个车辆 ID 在 CSV 文件中出现多次,则使用车辆 ID 作为字典中的键会失败。您可能会发现创建一个数组或列表更有用,然后您可以根据需要使用 Linq 进行查询,例如替换创建字典的行

var dictionary = records.ToDictionary(r => r.VehicleID, r => r);

var csvData = records.ToArray();

然后你可以做类似的事情

var bookingsForVehicle = csvData.Where(d => d.VehicleID == 42);

之所以调用 .ToArray() 或 .ToList() 之类的方法,是为了避免多次枚举结果,导致文件被多次解析。

【讨论】:

  • 我会试一试,一旦我开始工作,我就会接受它。谢谢你对我的坚持。
【解决方案2】:

我维护了一些可以帮助解决此问题的库:Sylvan.Data.Csv and Sylvan.Data。这些库提供的 API 与 Eric J. 建议的 CsvHelper 库非常相似。主要区别在于您不需要手动映射列名称,假设属性名称是 CSV 中标题的“PascalCase”转换,这可能是一种边际便利。我的数据绑定器(GetRecords&lt;T&gt; 后面的代码)是 DbDataReader-agnostic,因此它也可以与其他数据源一起使用,例如 SqlServer 结果集或我的Sylvan.Data.Excel 库(请参阅下面注释掉的行)。这些库也是fastest-in-class in the .NET ecosystem

CsvHelper 可能提供了一些我的库没有的功能,但对于像这样的直接映射,代码几乎相同。修改后的 Eric J.s 示例:

using Sylvan.Data;
using Sylvan.Data.Csv;
//using Sylvan.Data.Excel;

using (var data = CsvDataReader.Create("bookings.csv"))
//using (var data = ExcelDataReader.Create("bookings.xlsx"))
{
    var dictionary =
        data.GetRecords<Booking>()
        .ToDictionary(r => r.VehicleId, r => r);
}

public enum BookingStatus
{
    Booked,
    // TODO: Add other statuses
}

public class Booking
{
    public int VehicleId { get; set; }
    public string CustomerId { get; set; }
    public DateTime BookedDate { get; set; }
    public int BookedDateWeekNumber { get; set; }
    public int NumberOfDaysBooked { get; set; }
    public BookingStatus BookingStatus { get; set; }
}

【讨论】:

    猜你喜欢
    • 2013-06-08
    • 2021-05-01
    • 2017-07-21
    • 2018-10-12
    • 2011-11-17
    • 2017-09-23
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多