我正在尝试阅读*.csv
- 文件。
*.csv
- 文件由两个以分号分隔的列(“; ”)组成。
我能够使用StreamReader读取*.csv
- 文件,并能够使用Split()
函数分隔每一行。我想将每列存储到一个单独的数组中然后显示它。
有可能吗?
答案 0 :(得分:335)
你可以这样做:
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]);
}
}
}
答案 1 :(得分:126)
我最喜欢的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
答案 2 :(得分:71)
LINQ方式:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^错误 - 由尼克编辑
原来的回答者似乎试图用一个二维数组填充csv
- 一个包含数组的数组。第一个数组中的每个项都包含一个数组,表示该行号,嵌套数组中的每个项目都包含该特定列的数据。
var csv = from line in lines
select (line.Split(',')).ToArray();
答案 3 :(得分:33)
我通常使用这个parser from codeproject,因为它有一堆字符转义和它为我处理的类似。
答案 4 :(得分:29)
刚遇到这个图书馆:https://github.com/JoshClose/CsvHelper
非常直观且易于使用。还有一个nuget包,可以快速实现:http://nuget.org/packages/CsvHelper/1.17.0。我似乎也积极维护。
将其配置为使用分号很容易:https://github.com/JoshClose/CsvHelper/wiki/Custom-Configurations
答案 5 :(得分:29)
这是我对最高投票答案的变体:
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];
}
答案 6 :(得分:26)
您无法立即创建数组,因为您需要从头开始知道行数(这需要两次读取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);
N.B。
请注意,这只是一个非常简单的示例。使用string.Split
不会考虑某些记录中包含分隔符;
的情况
为了更安全的方法,请考虑在nuget上使用一些csv特定库,如CsvHelper。
答案 7 :(得分:11)
如果你需要跳过(头部)线和/或列,你可以使用它来创建一个二维数组:
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。您可以使用以下代码轻松获取标题和第1列:
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
语句之间。
答案 8 :(得分:9)
您可以在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;
}
答案 9 :(得分:4)
var firstColumn = new List<string>();
var lastColumn = new List<string>();
// your code for reading CSV file
foreach(var line in file)
{
var array = line.Split(';');
firstColumn.Add(array[0]);
lastColumn.Add(array[1]);
}
var firstArray = firstColumn.ToArray();
var lastArray = lastColumn.ToArray();
答案 10 :(得分:4)
这是一个特殊情况,其中一个数据字段以分号(“;”)作为其数据的一部分,在这种情况下,上述大部分答案都将失败。
解决方案就是
string[] csvRows = System.IO.File.ReadAllLines(FullyQaulifiedFileName);
string[] fields = null;
List<string> lstFields;
string field;
bool quoteStarted = false;
foreach (string csvRow in csvRows)
{
lstFields = new List<string>();
field = "";
for (int i = 0; i < csvRow.Length; i++)
{
string tmp = csvRow.ElementAt(i).ToString();
if(String.Compare(tmp,"\"")==0)
{
quoteStarted = !quoteStarted;
}
if (String.Compare(tmp, ";") == 0 && !quoteStarted)
{
lstFields.Add(field);
field = "";
}
else if (String.Compare(tmp, "\"") != 0)
{
field += tmp;
}
}
if(!string.IsNullOrEmpty(field))
{
lstFields.Add(field);
field = "";
}
// This will hold values for each column for current row under processing
fields = lstFields.ToArray();
}
答案 11 :(得分:4)
大家好,我为此创建了一个静态类。 +列检查 +配额标志删除
public static class CSV
{
public static List<string[]> Import(string file, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
{
return ReadCSVFile(file, csvDelimiter, ignoreHeadline, removeQuoteSign);
}
private static List<string[]> ReadCSVFile(string filename, char csvDelimiter, bool ignoreHeadline, bool removeQuoteSign)
{
string[] result = new string[0];
List<string[]> lst = new List<string[]>();
string line;
int currentLineNumner = 0;
int columnCount = 0;
// Read the file and display it line by line.
using (System.IO.StreamReader file = new System.IO.StreamReader(filename))
{
while ((line = file.ReadLine()) != null)
{
currentLineNumner++;
string[] strAr = line.Split(csvDelimiter);
// save column count of dirst line
if (currentLineNumner == 1)
{
columnCount = strAr.Count();
}
else
{
//Check column count of every other lines
if (strAr.Count() != columnCount)
{
throw new Exception(string.Format("CSV Import Exception: Wrong column count in line {0}", currentLineNumner));
}
}
if (removeQuoteSign) strAr = RemoveQouteSign(strAr);
if (ignoreHeadline)
{
if(currentLineNumner !=1) lst.Add(strAr);
}
else
{
lst.Add(strAr);
}
}
}
return lst;
}
private static string[] RemoveQouteSign(string[] ar)
{
for (int i = 0;i< ar.Count() ; i++)
{
if (ar[i].StartsWith("\"") || ar[i].StartsWith("'")) ar[i] = ar[i].Substring(1);
if (ar[i].EndsWith("\"") || ar[i].EndsWith("'")) ar[i] = ar[i].Substring(0,ar[i].Length-1);
}
return ar;
}
}
答案 12 :(得分:2)
开源Angara.Table库允许将CSV加载到类型列中,因此您可以从列中获取数组。每个列都可以按名称或索引编制索引。请参阅http://predictionmachines.github.io/Angara.Table/saveload.html。
图书馆遵循RFC4180 for CSV;它启用了类型推断和多行字符串。
示例:
using System.Collections.Immutable;
using Angara.Data;
using Angara.Data.DelimitedFile;
...
ReadSettings settings = new ReadSettings(Delimiter.Semicolon, false, true, null, null);
Table table = Table.Load("data.csv", settings);
ImmutableArray<double> a = table["double-column-name"].Rows.AsReal;
for(int i = 0; i < a.Length; i++)
{
Console.WriteLine("{0}: {1}", i, a[i]);
}
您可以使用Column类型查看列类型,例如
Column c = table["double-column-name"];
Console.WriteLine("Column {0} is double: {1}", c.Name, c.Rows.IsRealColumn);
由于库专注于F#,您可能需要添加对FSharp.Core 4.4程序集的引用;点击“添加参考”&#39;在项目上选择FSharp.Core 4.4&#34; Assemblies&#34; - &GT; &#34;扩展&#34;
答案 13 :(得分:1)
我多年来一直在使用csvreader.com(付费组件),我从未遇到过任何问题。它坚固,小巧,快速,但您必须付出代价。您可以将分隔符设置为您喜欢的任何内容。
using (CsvReader reader = new CsvReader(s) {
reader.Settings.Delimiter = ';';
reader.ReadHeaders(); // if headers on a line by themselves. Makes reader.Headers[] available
while (reader.ReadRecord())
... use reader.Values[col_i] ...
}
答案 14 :(得分:1)
我只是学生正在研究我的硕士论文,但这是我解决它的方式,对我来说效果很好。首先,您从目录中选择文件(仅以csv格式),然后将数据放入列表中。
List<float> t = new List<float>();
List<float> SensorI = new List<float>();
List<float> SensorII = new List<float>();
List<float> SensorIII = new List<float>();
using (OpenFileDialog dialog = new OpenFileDialog())
{
try
{
dialog.Filter = "csv files (*.csv)|*.csv";
dialog.Multiselect = false;
dialog.InitialDirectory = ".";
dialog.Title = "Select file (only in csv format)";
if (dialog.ShowDialog() == DialogResult.OK)
{
var fs = File.ReadAllLines(dialog.FileName).Select(a => a.Split(';'));
int counter = 0;
foreach (var line in fs)
{
counter++;
if (counter > 2) // Skip first two headder lines
{
this.t.Add(float.Parse(line[0]));
this.SensorI.Add(float.Parse(line[1]));
this.SensorII.Add(float.Parse(line[2]));
this.SensorIII.Add(float.Parse(line[3]));
}
}
}
}
catch (Exception exc)
{
MessageBox.Show(
"Error while opening the file.\n" + exc.Message,
this.Text,
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
}
答案 15 :(得分:1)
我的简单静态方法将 csv 行转换为数组,并将数组转换为 csv 行。
public static string CsvRowFromStringArray(string[] csvData, char fieldSeparator = ',', char stringQuote = '"')
{
csvData = csvData.Select(element => {
if (element.Contains(stringQuote))
{
element = element.Replace(stringQuote.ToString(), stringQuote.ToString() + stringQuote.ToString());
}
if (element.Contains(fieldSeparator))
{
element = "\"" + element + "\"";
}
return element;
}).ToArray();
return string.Join(fieldSeparator.ToString(), csvData);
}
public static string[] CsvRowToStringArray(string csvRow, char fieldSeparator = ',', char stringQuote = '"')
{
char tempQuote = (char)162;
while (csvRow.Contains(tempQuote)) { tempQuote = (char)(tempQuote + 1); }
char tempSeparator = (char)(tempQuote + 1);
while (csvRow.Contains(tempSeparator)) { tempSeparator = (char)(tempSeparator + 1); }
csvRow = csvRow.Replace(stringQuote.ToString() + stringQuote.ToString(), tempQuote.ToString());
var csvArray = csvRow.Split(fieldSeparator).ToList().Aggregate("",
(string row, string item) =>
{
if (row.Count((ch) => ch == stringQuote) % 2 == 0) { return row + (row.Length > 0 ? tempSeparator.ToString() : "") + item; }
else { return row + fieldSeparator + item; }
},
(string row) => row.Split(tempSeparator).Select((string item) => item.Trim(stringQuote).Replace(tempQuote, stringQuote))).ToArray();
return csvArray;
}
private bool CsvTestError()
{
string correctString = "0;a;\"b; c\";\"\"xy;\"this;is; one \"\"long; cell\"\"\"";
string[] correctArray = new string[] { "0", "a", "b; c", "\"xy", "this;is; one \"long; cell\"" };
bool error = string.Join("°", CsvRowToStringArray(correctString, ';')) != string.Join("°", correctArray);
error = (CsvRowFromStringArray(correctArray, ';') != correctString) || error;
return error;
}
答案 16 :(得分:0)
还是错的。你需要补偿&#34;&#34;在引号中。 这是我的解决方案Microsoft style csv。
/// <summary>
/// Microsoft style csv file. " is the quote character, "" is an escaped quote.
/// </summary>
/// <param name="fileName"></param>
/// <param name="sepChar"></param>
/// <param name="quoteChar"></param>
/// <param name="escChar"></param>
/// <returns></returns>
public static List<string[]> ReadCSVFileMSStyle(string fileName, char sepChar = ',', char quoteChar = '"')
{
List<string[]> ret = new List<string[]>();
string[] csvRows = System.IO.File.ReadAllLines(fileName);
foreach (string csvRow in csvRows)
{
bool inQuotes = false;
List<string> fields = new List<string>();
string field = "";
for (int i = 0; i < csvRow.Length; i++)
{
if (inQuotes)
{
// Is it a "" inside quoted area? (escaped litteral quote)
if(i < csvRow.Length - 1 && csvRow[i] == quoteChar && csvRow[i+1] == quoteChar)
{
i++;
field += quoteChar;
}
else if(csvRow[i] == quoteChar)
{
inQuotes = false;
}
else
{
field += csvRow[i];
}
}
else // Not in quoted region
{
if (csvRow[i] == quoteChar)
{
inQuotes = true;
}
if (csvRow[i] == sepChar)
{
fields.Add(field);
field = "";
}
else
{
field += csvRow[i];
}
}
}
if (!string.IsNullOrEmpty(field))
{
fields.Add(field);
field = "";
}
ret.Add(fields.ToArray());
}
return ret;
}
}
答案 17 :(得分:0)
我有一个正在完成你需要的库。
前段时间我写了一个简单而快速的库来处理CSV文件。您可以通过以下链接找到它:https://github.com/ukushu/DataExporter
与2维数组一样使用CSV。完全像你需要的那样。
例如,如果您需要第3行的所有值,则只需编写:
Csv csv = new Csv();
csv.FileOpen("c:\\file1.csv");
var allValuesOf3rdRow = csv.Rows[2];
或阅读
的第二个单元格var value = csv.Rows[2][1];
答案 18 :(得分:0)
我花了几个小时寻找合适的库,但是最后我写了自己的代码:) 您可以使用任何所需的工具读取文件(或数据库),然后将以下例程应用于每一行:
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();
}
答案 19 :(得分:-1)
使用CsvFramework;
使用System.Collections.Generic;
命名空间CvsParser {
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public int Quantity { get; set; }
public int Amount { get; set; }
public List<OrderItem> OrderItems { get; set; }
}
public class Address
{
public int Id { get; set; }
public int CustomerId { get; set; }
public string Name { get; set; }
}
public class OrderItem
{
public int Id { get; set; }
public int OrderId { get; set; }
public string ProductName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var customerLines = System.IO.File.ReadAllLines(@"Customers.csv");
var orderLines = System.IO.File.ReadAllLines(@"Orders.csv");
var orderItemLines = System.IO.File.ReadAllLines(@"OrderItemLines.csv");
CsvFactory.Register<Customer>(builder =>
{
builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
builder.Add(a => a.Name).Type(typeof(string)).Index(1);
builder.AddNavigation(n => n.Orders).RelationKey<Order, int>(k => k.CustomerId);
}, false, ',', customerLines);
CsvFactory.Register<Order>(builder =>
{
builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
builder.Add(a => a.CustomerId).Type(typeof(int)).Index(1);
builder.Add(a => a.Quantity).Type(typeof(int)).Index(2);
builder.Add(a => a.Amount).Type(typeof(int)).Index(3);
builder.AddNavigation(n => n.OrderItems).RelationKey<OrderItem, int>(k => k.OrderId);
}, true, ',', orderLines);
CsvFactory.Register<OrderItem>(builder =>
{
builder.Add(a => a.Id).Type(typeof(int)).Index(0).IsKey(true);
builder.Add(a => a.OrderId).Type(typeof(int)).Index(1);
builder.Add(a => a.ProductName).Type(typeof(string)).Index(2);
}, false, ',', orderItemLines);
var customers = CsvFactory.Parse<Customer>();
}
}
}