在.NET中编写CSV文件

44

我有一个需要将数据集导出为CSV文件的需求。

我花了一段时间搜索了一些规则,发现写CSV文件时存在许多规则和例外。

http://knab.ws/blog/index.php?/archives/3-CSV-file-parser-and-writer-in-C-Part-1.html http://bytes.com/topic/c-sharp/answers/236875-problems-streamwriter-output-csv http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/0073fcbb-adab-40f0-b768-4bba803d3ccd

所以现在生成CSV文件并不是简单地用逗号分隔字符串的过程,我已经搜索了现有的CSV编写程序,包括第三方程序或在.net框架中(希望如此!)自带的程序。

编辑:新链接:http://www.thinqlinq.com/Post.aspx/Title/LINQ-to-CSV-using-DynamicObject-and-TextFieldParser

TextFieldParser是一个VB对象(可以从C#引用),可以自动解析CSV文件。:)

我想知道是否有人知道任何方便的.Net(2.0-> 3.5和4.0)库可用于生成格式正确的CSV文件。

此外,是否有任何生成CSV文件的规则集。

CSV的读取和解析有很多细节,但关于写入CSV的内容则不够详细(好的,我知道这正相反:P)。

http://www.codeproject.com/KB/database/CsvReader.aspx

任何帮助将不胜感激 :)

我找到了另一篇更详细的CSV规则文章:http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm

一个不错的第三方库是Linq-to-CSV(不是框架库):http://www.codeproject.com/KB/linq/LINQtoCSV.aspx

谢谢大家的帮助。 我决定创建一个简单的静态类来执行特殊字符替换(Chris提到的)。

如果我需要查询CSV文件,我会看CodeProjects实现的Linq-to-CSV。

再次感谢:)


我认为既然你是导出者,写作时可以比较放松,只要遵循一般规则,大多数程序如Excel都能够读取它们。 - AndersK
没错。我很不幸地处于编写一个没有指定潜在用途的“导出”功能的位置。我假设99%的情况下这将是Excel或其他应用程序的SSIS包(不太可能)。但我只能做出假设。 - Russell
你可以尝试我的非常轻量级分隔符文件写入程序:https://gist.github.com/eranbetzalel/5371817#file-delimitedfilewriter-cs - Eran Betzalel
11个回答

51

CsvHelper(我维护的一个库)也可以通过NuGet获得。

CsvHelper可以自动将您的类对象写入文件。

var myObj = new MyCustomClass
{
    Prop1 = "one",
    Prop2 = 2
};
var streamWriter = // Create a writer to somewhere...
var csvWriter = new CsvWriter( streamWriter );

// You can write a single record.
csvWriter.WriteRecord( myObj );

// You can also write a collection of records.
var myRecords = new List<MyCustomClass>{ myObj };
csvWriter.WriteRecords( myRecords );

顺便提一下,CsvHelper 新增了一些映射功能,允许你在不使用属性的情况下映射你的类。你可以使用流畅的映射类来实现,这样就可以映射到你无法控制的类了。 - Josh Close

21

如果您的单元格中包含任何逗号,请用双引号将整个单元格框起来,例如:

cell 1,cell 2,"This is one cell, even with a comma",cell4,etc

如果你想要一个双引号,就输入两个双引号,例如:

cell 1,cell 2,"This is my cell and it has ""quotes"" in it",cell 4,etc

在处理日期时,建议始终使用ISO格式(例如yyyy-mm-dd hh:mm:ss),这样就不会有太大问题。


2
它们是唯一的“规则”吗?例如,换行符怎么办?您知道这些规则/要求的任何参考资料吗?我假设(从搜索中)这些文件类型没有标准,只有专有要求(例如,适用于Excel的要求:P)。感谢您的回答。 - Russell
基本上,我会使用任何与Excel兼容的方法。至于换行符,C#的各种AppendLine和WriteLine函数似乎都会附加\r\n,这似乎与Excel一致。 - Chris
7
根据http://en.wikipedia.org/wiki/Comma-separated_values,如果你需要严格遵循CSV格式要求,那么这个答案对于CSV的格式要求来说过于简单了。 - Shane Courtrille
2
顺便提一下日期格式:你引用的不是ISO格式(ISO 8601使用“T”而不是空格来分隔日期和时间)。 - Kos
这个链接及其中的链接提供了一些有用的信息,并介绍了CSV中缺乏标准的情况 - http://tools.ietf.org/html/rfc4180 - Steam
显示剩余2条评论

18

我只想补充一点,有一份RFC规范了CSV格式,这是我认为的权威来源。


1
谢谢Richard,这是非常详细的信息 :) - Russell

6

我广泛使用过filehelpers,它在生成CSV方面非常出色。


谢谢,FileHelpers看起来是一个非常方便(+开源)的库。不幸的是,在这种情况下,我无法向我的对象添加属性,而我想将其转换为CSV格式。使用.Net反编译器,我无法通过传递值/列表的方式来完成这项工作。你知道是否有可能实现吗? - Russell
你可以创建一些新的“仅生成器”类,并使用AutoMapper将真实类映射到生成器类,然后使用FileHelpers将这些类写出。我以前做过这个,很简单。 - lomaxx
文件助手真的可以处理CSV吗?当然,它们有分隔符,但这与带引号规则的CSV不同。 - Shane Courtrille

4

这里是你可以使用的函数,用于从字符串列表(也可以使用IEnumerable(Of String)或字符串数组)生成CSV文件的一行:

Function CreateCSVRow(strArray As List(Of String)) As String
    Dim csvCols As New List(Of String)
    Dim csvValue As String
    Dim needQuotes As Boolean
    For i As Integer = 0 To strArray.Count() - 1
        csvValue = strArray(i)
        needQuotes = (csvValue.IndexOf(",", StringComparison.InvariantCulture) >= 0 _
                      OrElse csvValue.IndexOf("""", StringComparison.InvariantCulture) >= 0 _
                      OrElse csvValue.IndexOf(vbCrLf, StringComparison.InvariantCulture) >= 0)
        csvValue = csvValue.Replace("""", """""")
        csvCols.Add(If(needQuotes, """" & csvValue & """", csvValue))
    Next
    Return String.Join(",", csvCols.ToArray())
End Function

我认为,从VB.NET转换到C#并不难。

谢谢您提供的信息,Evgeny。我相信这对于遇到这个问题的人会很有帮助。 :) - Russell


3

我知道你说你已经找到了答案,但我想为你提到的LINQtoCSV库投一票。我在几个项目中使用过它,对于保持业务代码的整洁和不涉及文件格式的细节/特殊性方面非常有效。

也许在你的特定情况下编写导出器并不太困难,但这个库的好处在于它是双向的。如果你发现自己将来需要消费CSV,它并不需要太多额外的代码,或者它可以为你提供一个一致的库用于未来的项目。


谢谢,看起来确实很方便。不同的项目有不同的要求和优先级,因此不同的解决方案可能更适合不同的项目。感谢您的支持,如果您喜欢它,请别忘了点赞。 :) - Russell

2
您可以使用ODBC(通过OdbcConnection和适当的连接字符串)来读写CSV文件。这对于生成CSV文件应该是相当不错的,并且会处理引用等问题;但是,我在使用它来读取其他程序生成的CSV文件时遇到了一些问题。

1
谢谢,有关于这种方法入门的参考资料吗? - Russell
1
如果你在谷歌上搜索"odbc csv file",会出现很多链接。排名靠前的一个是http://www.c-sharpcorner.com/UploadFile/mahesh/AccessTextDb12052005071306AM/AccessTextDb.aspx-- 注意,你需要向下滚动到页面底部才能找到C#代码! - itowlson

2

另一个需要加入的规则是:使用逗号作为字段分隔符而不是字段终止符。原因是在行末添加逗号可能会产生歧义:它是否具有意义或者表示其后面有一个NULL值?


非常好的观点。最好有一个“行尾”分隔符,而不是假定为换行符。例如,不同的操作系统使用不同的字符! - Russell
1
CSV格式规定每行的终止符为CRLF("\r\n")。 - Gusdor

0

我找到了这个非常不错的重要链接。还没有尝试过,会告诉你它的效果如何!

http://www.codeproject.com/KB/linq/LINQtoCSV.aspx

仔细看来,这个实现基本上只使用了基本规则:

特殊字符 = \n \" 和分隔符。

如果发现特殊字符,则用引号括起来。 将引号替换为双引号。

本质上是Chris提到的规则。 我认为最简单的方法是根据简单规则创建我的辅助方法,并根据用户需求进行修订。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接