作为最近项目的一部分,我必须从CSV文件中读取和写入并放入c#中的网格视图中。最后决定使用一个现成的解析器为我做的工作。
因为我喜欢做那种东西,所以我想知道如何写自己的东西。
到目前为止,我所做的就是:
//Read the header
StreamReader reader = new StreamReader(dialog.FileName);
string row = reader.ReadLine();
string[] cells = row.Split(',');
//Create the columns of the dataGridView
for (int i = 0; i < cells.Count() - 1; i++)
{
DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
column.Name = cells[i];
column.HeaderText = cells[i];
dataGridView1.Columns.Add(column);
}
//Display the contents of the file
while (reader.Peek() != -1)
{
row = reader.ReadLine();
cells = row.Split(',');
dataGridView1.Rows.Add(cells);
}
我的问题:继续这样一个明智的想法,如果是(或不是),我将如何正确地测试它?
答案 0 :(得分:7)
作为一项编程练习(用于学习和获得经验),这可能是一件非常合理的事情。对于生产代码,使用现有库可能更好,主要是因为工作已经完成。使用CSV解析器可以解决很多问题。例如(随机离开我的头顶):
如果您在非常受控的环境中拥有非常特定的输入格式,则可能不需要处理所有这些。
答案 1 :(得分:2)
获取(或制作)一些CSV数据,并使用Unit Tests或NUnit撰写Visual Studio Testing Tools。
请务必测试像
这样的边缘情况"csv","Data","with","a","trailing","comma",
和
"csv","Data","with,","commas","and","""quotes""","in","it"
答案 2 :(得分:1)
......正在继续这样一个明智的想法......?
由于您将此作为学习练习,因此您可能需要深入了解lexing和parsing理论。如Stop Rolling Your Own CSV Parser!中所述,您当前的方法将很快显示其缺点。并不是解析CSV数据很困难。 (事实并非如此。)只是大多数CSV解析器项目将问题视为文本拆分问题而不是解析问题。如果您花时间定义CSV“语言”,解析器几乎会自行编写。
file = [header CRLF] record *(CRLF record) [CRLF]
header = name *(COMMA name)
record = field *(COMMA field)
name = field
field = (escaped / non-escaped)
escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
non-escaped = *TEXTDATA
COMMA = %x2C
CR = %x0D ;as per section 6.1 of RFC 2234
DQUOTE = %x22 ;as per section 6.1 of RFC 2234
LF = %x0A ;as per section 6.1 of RFC 2234
CRLF = CR LF ;as per section 6.1 of RFC 2234
TEXTDATA = %x20-21 / %x23-2B / %x2D-7E
此语法显示如何构建单个字符以创建越来越复杂的语言元素。 (正如所写,定义从复杂到简单的方向相反。)
如果从语法开始,可以编写镜像非终端语法元素(小写项)的解析函数。 Julian M Bucknall在Writing a parser for CSV data中描述了这个过程。使用解析器生成器查看Test-Driven Development with ANTLR以获取相同进程的示例。
请注意,没有人接受CSV定义。野外的CSV数据无法保证实施所有RFC 4180建议。
答案 3 :(得分:0)
解析CSV文件并不困难,但它不仅仅是调用String.Split()
。
你打破了每个逗号的界限。但是字段可能包含嵌入的逗号。在这些情况下,CSV将字段用双引号括起来。因此,您还必须查找双引号并忽略这些引号中的逗号。此外,字段甚至可以包含嵌入的双引号。双引号必须出现在双引号内并且“加倍”以表示引号是文字字符。
如果您想了解我是如何做到的,可以查看this article。
答案 4 :(得分:0)
这来自 http://www.gigawebsolution.com/Posts/Details/61/Building-a-Simple-CSV-Parser-in-C#
public interface ICsvReaderWriter
{
List<string[]> Read(string filePath, char delimiter);
void Write(string filePath, List<string[]> lines, char delimiter);
}
public class CsvReaderWriter : ICsvReaderWriter
{
public List<string[]> Read(string filePath, char delimiter)
{
var fileContent = new List<string[]>();
using (var reader = new StreamReader(filePath, Encoding.Unicode))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (!string.IsNullOrEmpty(line))
{
fileContent.Add(line.Split(delimiter));
}
}
}
return fileContent;
}
public void Write(string filePath, List<string[]> lines, char delimiter)
{
using (var writer = new StreamWriter(filePath, true, Encoding.Unicode))
{
foreach (var line in lines)
{
var data = line.Aggregate(string.Empty,
(current, column) => current +
string.Format("{0}{1}", column,delimiter))
.TrimEnd(delimiter);
writer.WriteLine(data);
}
}
}
}