我正试图读取一个 *.csv
文件。
*.csv
文件由两列组成,用分号(;)分隔。
我可以使用 StreamReader 读取 *.csv
文件,并使用 Split()
函数将每一行分开。我希望将每个列存储到不同的数组中,然后显示出来。
这种操作是否可行?
我正试图读取一个 *.csv
文件。
*.csv
文件由两列组成,用分号(;)分隔。
我可以使用 StreamReader 读取 *.csv
文件,并使用 Split()
函数将每一行分开。我希望将每个列存储到不同的数组中,然后显示出来。
这种操作是否可行?
你可以这样做:
using System.IO;
static void Main(string[] args)
{
using(var reader = new StreamReader(@"C:\test.csv"))
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
listA.Add(values[0]);
listB.Add(values[1]);
}
}
}
using
语句,或者至少手动调用 Close()
方法关闭 reader
对象,因为它是一个可被释放的资源(IDisposable
)。 - Assaf Israelcolumn1;"字符串中有特殊;字符";column3
的CSV格式 - https://tools.ietf.org/html/rfc4180 - Ole K我最喜欢的CSV解析器是.NET库内置的解析器。它是Microsoft.VisualBasic命名空间中的一个隐藏宝藏。 以下是样例代码:
using Microsoft.VisualBasic.FileIO;
var path = @"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
// Skip the row with the column names
csvParser.ReadLine();
while (!csvParser.EndOfData)
{
// Read current line fields, pointer moves to the next line.
string[] fields = csvParser.ReadFields();
string Name = fields[0];
string Address = fields[1];
}
}
请记得添加对 Microsoft.VisualBasic
的引用
关于解析器的更多细节,请参见此处:http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
Microsoft.VisualBasic
框架程序集的引用,因为它通常不会被默认引用。 - apokryfosLINQ的写法:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^错误 - 由Nick编辑
原本回答者试图用一个二维数组(包含多个数组)来填充csv
。第一个数组中的每个项目都包含一个表示该行号的数组,嵌套数组中的每个项目都包含特定列的数据。
var csv = from line in lines
select (line.Split(',')).ToArray();
刚刚找到这个库:https://github.com/JoshClose/CsvHelper
非常直观和易于使用。还有一个NuGet包,使其快速实现:https://www.nuget.org/packages/CsvHelper/27.2.1。看起来也在积极维护,我很喜欢。
将其配置为使用半角分号很容易:https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations
Microsoft.VisualBasic.FileIO.TextFieldParser
相比较?(参考@Habeeb的答案) - bovender你不能立即创建一个数组,因为你需要从一开始就知道行数(这将需要两次读取csv文件)
你可以将值存储在两个List<T>
中,然后使用它们或者使用List<T>.ToArray()
将其转换成数组。
非常简单的示例:
var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader("filename.csv"))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(';');
column1.Add(splits[0]);
column2.Add(splits[1]);
}
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
Console.WriteLine(element);
// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
Console.WriteLine(element);
请注意,这只是一个非常简单的例子。使用 string.Split
并不能解决某些记录内部包含分隔符 ;
的情况。为了更安全的方法,请考虑使用一些特定于 csv 的库,如 nuget 上的 CsvHelper。
;
作为值的一部分,例如 "value with ; inside it"
。CSV 使用双引号包围包含特殊字符的值,以表示它是一个字面字符串。 - ChickenFeet我通常使用来自CodeProject的解析器,因为它可以处理许多字符转义和类似问题。
这是我对得票最高答案的改编:
var contents = File.ReadAllText(filename).Split('\n');
var csv = from line in contents
select line.Split(',').ToArray();
然后,csv
变量可以像以下示例中使用:
int headerRows = 5;
foreach (var row in csv.Skip(headerRows)
.TakeWhile(r => r.Length > 1 && r.Last().Trim().Length > 0))
{
String zerothColumnValue = row[0]; // leftmost column
var firstColumnValue = row[1];
}
如果您需要跳过行和/或列,可以使用以下代码创建一个二维数组:
var lines = File.ReadAllLines(path).Select(a => a.Split(';'));
var csv = (from line in lines
select (from col in line
select col).Skip(1).ToArray() // skip the first column
).Skip(2).ToArray(); // skip 2 headlines
如果您需要在进一步处理数据之前对其进行整形,这将非常有用(假设前两行是标题,第一列是行标题 - 由于您只想考虑数据,因此不需要在数组中拥有行标题)。
N.B. 您可以使用以下代码轻松获取标题和第一列:
var coltitle = (from line in lines
select line.Skip(1).ToArray() // skip 1st column
).Skip(1).Take(1).FirstOrDefault().ToArray(); // take the 2nd row
var rowtitle = (from line in lines select line[0] // take 1st column
).Skip(2).ToArray(); // skip 2 headlines
此代码示例假设您的*.csv
文件具有以下结构:
where line.Any(a=>!string.IsNullOrWhiteSpace(a))
在上面的LINQ代码示例中,from
和select
语句之间。
您可以在C#中使用Microsoft.VisualBasic.FileIO.TextFieldParser dll以获得更好的性能。
从上述文章中获取下面的代码示例:
static void Main()
{
string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv";
DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
Console.WriteLine("Rows count:" + csvData.Rows.Count);
Console.ReadLine();
}
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
}
return csvData;
}
我花了几个小时寻找一个合适的库,但最终我写了自己的代码 :) 你可以用任何工具读取文件(或数据库),然后对每一行应用以下例程:
private static string[] SmartSplit(string line, char separator = ',')
{
var inQuotes = false;
var token = "";
var lines = new List<string>();
for (var i = 0; i < line.Length; i++) {
var ch = line[i];
if (inQuotes) // process string in quotes,
{
if (ch == '"') {
if (i<line.Length-1 && line[i + 1] == '"') {
i++;
token += '"';
}
else inQuotes = false;
} else token += ch;
} else {
if (ch == '"') inQuotes = true;
else if (ch == separator) {
lines.Add(token);
token = "";
} else token += ch;
}
}
lines.Add(token);
return lines.ToArray();
}