技術(shù)頻道導(dǎo)航
HTML/CSS
.NET技術(shù)
IIS技術(shù)
PHP技術(shù)
Js/JQuery
Photoshop
Fireworks
服務(wù)器技術(shù)
操作系統(tǒng)
網(wǎng)站運(yùn)營(yíng)

贊助商

分類目錄

贊助商

最新文章

搜索

C# .NET使用CsvHelper讀寫CSV文件,快速又易用

作者:admin    時(shí)間:2023-5-18 20:40:28    瀏覽:

C# .NET 解析并讀寫 CSV 文件,本文詳細(xì)介紹如何使用 CsvHelper 來完成這個(gè)操作。

 C# .NET使用CsvHelper讀寫CSV文件,快速又易用

CsvHelper 介紹

CsvHelper 是一個(gè)用于讀取和寫入CSV文件的.NET庫(kù),非常快速、靈活且易于使用。

CsvHelper 有如下幾大特征:

  • 快速
    即時(shí)編譯類以獲得極快的性能。
  • 靈活
    寫入時(shí)保守,讀取時(shí)自由。
  • 便于使用
    讀取和寫入就像 GetRecords<T>()WriteRecords(records) 一樣簡(jiǎn)單。無(wú)需配置。
  • 高度可配置
    具有豐富的映射和屬性系統(tǒng),可將任何類型的 CSV 文件配置為任何類型的類。
  • 優(yōu)雅的回退
    當(dāng)讀取非標(biāo)準(zhǔn)文件時(shí),回退將匹配 MS Excel 解析。
  • 可在任何地方運(yùn)行
    CsvHelper 建立在 .NET Standard 2.0 之上,這使得它幾乎可以在任何地方運(yùn)行。如果需要,可以使用舊版本的 .NET。
  • 符合RFC 4180
    遵守 RFC 4180 標(biāo)準(zhǔn)以確??缦到y(tǒng)的兼容性。
  • 內(nèi)存使用率低
    讀取記錄將產(chǎn)生結(jié)果,因此一次只有一條記錄在內(nèi)存中。
  • 開源
    許多貢獻(xiàn)者幫助使 CsvHelper 成為今天偉大的庫(kù)。完全免費(fèi)用于商業(yè)用途。在MS-PL和 Apache 2下獲得雙重許可。
  • Linux模式
    常見 Linux/SerDe 文件的模式,其中使用轉(zhuǎn)義字符而不是 RFC 4180 的字段引用。
  • 字段緩存
    CSV 文件中存在重復(fù)數(shù)據(jù)時(shí)使用字段緩存的選項(xiàng)。這將減少內(nèi)存并加快解析時(shí)間。

CsvHelper 官網(wǎng):

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

開始安裝使用

下載

訪問下面官方地址下載安裝包。

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

安裝

包管理器控制臺(tái)

PM> Install-Package CsvHelper

.NET CLI 控制臺(tái)

> dotnet add package CsvHelper

文化資訊

CsvHelper 要求你指定要使用的 CultureInfo ,用于確定類型轉(zhuǎn)換時(shí)的默認(rèn)分隔符、默認(rèn)行結(jié)束符和格式。你也可以更改其中任何一個(gè)配置,為你的數(shù)據(jù)選擇合適的區(qū)域性。InvariantCulture在讀寫文件時(shí)可移植性最強(qiáng),因此將在大多數(shù)示例中使用。

換行符

默認(rèn)情況下,CsvHelper 將遵循RFC 4180并用\r\n編寫換行符,無(wú)論你在什么操作系統(tǒng)上運(yùn)行。CsvHelper 可以讀取\r\n\r\n不進(jìn)行任何配置更改。如果要以非標(biāo)準(zhǔn)格式讀取或?qū)懭?,可以更?code>NewLine。

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

讀 CSV 文件

假設(shè)我們有如下所示的 CSV 文件。

Id,Name
1,one
2,two

和一個(gè)看起來像這樣的類定義。

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

如果我們的類屬性名稱與我們的 CSV 文件頭名稱相匹配,我們可以在不進(jìn)行任何配置的情況下讀取該文件。

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

GetRecords<T>方法將返回一個(gè)IEnumerable<T>記錄,這意味著當(dāng)你迭代記錄時(shí),一次只返回一條記錄。這也意味著只有一小部分文件被讀入內(nèi)存。不過要小心。如果你執(zhí)行任何執(zhí)行 LINQ 投影的操作,例如調(diào)用.ToList(),整個(gè)文件將被讀入內(nèi)存。CsvReader是只向前的,所以如果你想對(duì)你的數(shù)據(jù)運(yùn)行任何 LINQ 查詢,你必須將整個(gè)文件拉入內(nèi)存。

假設(shè)我們的 CSV 文件名與我們的類屬性略有不同,我們不想讓我們的屬性匹配。

id,name
1,one
2,two

在這種情況下,名稱是小寫的。我們希望我們的屬性名稱是 Pascal 案例,這樣我們就可以更改我們的屬性與標(biāo)題名稱的匹配方式。

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,我們可以更改標(biāo)頭匹配的方式來匹配屬性名稱。標(biāo)頭和屬性名稱都在函數(shù)中運(yùn)行 PrepareHeaderForMatch。當(dāng)讀者需要找到要為標(biāo)題設(shè)置的屬性時(shí),它們現(xiàn)在將匹配。你可以使用此功能做其他事情,例如刪除空格或其他字符。

假設(shè) CSV 文件根本沒有標(biāo)題。

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 將使用屬性在類中的位置作為索引位置。但是這有一個(gè)問題,你不能依賴 .NET 中類成員的順序。我們可以通過將屬性映射到 CSV 文件中的某個(gè)位置來解決這個(gè)問題。

一種方法是使用屬性映射。

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

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

IndexAttribute允許你指定要將 CSV 字段用于屬性的哪個(gè)位置。

你也可以按名稱映射,讓我們使用之前的小寫標(biāo)題示例,看看我們?nèi)绾问褂脤傩远皇歉臉?biāo)題匹配。

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

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

你還可以使用許多其他屬性,請(qǐng)參閱如下網(wǎng)址。

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

如果我們無(wú)法控制要映射到的類,所以我們無(wú)法向其添加屬性怎么辦?這種情況下,我們可以使用fluentClassMap來做映射。

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

要使用映射,我們需要在上下文中注冊(cè)它。

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>();
}

創(chuàng)建類映射是在 CsvHelper 中映射文件的推薦方法,因?yàn)樗鼜?qiáng)大。

你也可以手動(dòng)讀取行。

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將向前進(jìn)行,ReadHeader會(huì)將行讀入 CsvHelper 作為標(biāo)題值。ReadHeader分隔Read并允許你在移動(dòng)到下一行之前對(duì)標(biāo)題行執(zhí)行其他操作。GetRecord也不會(huì)提前讓閱讀器允許你對(duì)你可能需要做的行做其他事情。你可能需要GetField針對(duì)單個(gè)字段或GetRecord多次調(diào)用以填充多個(gè)對(duì)象。

寫 CSV 文件

現(xiàn)在讓我們看看如何寫入 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" },
};

我們可以將記錄寫入文件而無(wú)需任何配置。

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

WriteRecords方法會(huì)將所有記錄寫入文件。寫入完成后,你應(yīng)該調(diào)用writer.Flush()以確保寫入器內(nèi)部緩沖區(qū)中的所有數(shù)據(jù)都已刷新到文件中。一旦一個(gè)using塊退出,writer 就會(huì)自動(dòng)刷新,所以我們不必在這里明確地這樣做。建議始終用using塊包裹任何IDisposable對(duì)象。該對(duì)象將在using塊退出后盡快處理自身(在我們的例子中也是 flush) 。

還記得我們?nèi)绾尾荒芤蕾?.NET 中的屬性順序嗎?如果我們正在編寫一個(gè)具有標(biāo)題的類,那沒關(guān)系,只要我們稍后使用標(biāo)題進(jìn)行閱讀即可。如果我們想在 CSV 文件中定位標(biāo)題,我們需要指定一個(gè)索引來保證它的順序。建議在編寫時(shí)始終設(shè)置索引。

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不會(huì)讓你前進(jìn)到下一行。 如果需要,NextRecordWriteHeader中分離允許你在標(biāo)題中寫入更多內(nèi)容。WriteRecord也不會(huì)使你前進(jìn)到下一行,從而使你能夠?qū)懭攵鄠€(gè)對(duì)象或用WriteField寫入單個(gè)字段。

示例

CsvHelper 讀寫CSV文件的示例,請(qǐng)參閱以下文章:

總結(jié)

本文詳細(xì)介紹了 C# .NET 使用 CsvHelper 讀寫CSV文件的方法。CSVHelper 是在 C# 中使用 CSV 的鼻祖,它根本不需要做任何映射,它自己處理雙引號(hào)、換行和枚舉解析,它可以處理完全自定義的映射、自定義類型轉(zhuǎn)換。此外,它的速度又快又易用,并且還是免費(fèi)的可用于商用用途,真的是一個(gè)讓人驚嘆的庫(kù)。

相關(guān)文章

標(biāo)簽: CSharp  asp.net  CsvHelper  CSV  
x
  • 站長(zhǎng)推薦
/* 左側(cè)顯示文章內(nèi)容目錄 */