C# 在DataGridView中读取CSV文件
我想将csv文件读入Datagridview。我希望有一个类和一个函数,可以像这样读取csv:C# 在DataGridView中读取CSV文件,c#,csv,datagridview,C#,Csv,Datagridview,我想将csv文件读入Datagridview。我希望有一个类和一个函数,可以像这样读取csv: class Import { public DataTable readCSV(string filePath) { DataTable dt = new DataTable(); using (StreamReader sr = new StreamReader(filePath)) {
class Import
{
public DataTable readCSV(string filePath)
{
DataTable dt = new DataTable();
using (StreamReader sr = new StreamReader(filePath))
{
string strLine = sr.ReadLine();
string[] strArray = strLine.Split(';');
foreach (string value in strArray)
{
dt.Columns.Add(value.Trim());
}
DataRow dr = dt.NewRow();
while (sr.Peek() >= 0)
{
strLine = sr.ReadLine();
strArray = strLine.Split(';');
dt.Rows.Add(strArray);
}
}
return dt;
}
}
并称之为:
Import imp = new Import();
DataTable table = imp.readCSV(filePath);
foreach(DataRow row in table.Rows)
{
dataGridView.Rows.Add(row);
}
结果是->创建了行,但单元格中没有数据 使用少量linq的第一个解决方案
下面是使用foreach循环的另一个版本
public DataTable readCSV(string filePath)
{
var dt = new DataTable();
// Creating the columns
foreach(var headerLine in File.ReadLines(filePath).Take(1))
{
foreach(var headerItem in headerLine.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
dt.Columns.Add(headerItem.Trim());
}
}
// Adding the rows
foreach(var line in File.ReadLines(filePath).Skip(1))
{
dt.Rows.Add(x.Split(';'));
}
return dt;
}
首先,我们使用File.ReadLines,它返回一个IEnumerable,它是行的集合。我们使用Take(1)只获取第一行,这应该是标题,然后使用SelectMany将在单个列表中转换Split方法返回的字符串数组,因此我们调用ToList,现在可以使用ForEach方法在DataTable中添加列
要添加行,我们仍然使用File.ReadLines,但现在我们跳过(1),这会跳过标题行,现在我们将使用Select创建集合
,然后再次调用ToList,最后调用ForEach在DataTable中添加行。.NET 4.0中提供了File.ReadLines
Obs.:不会读取所有行,它返回一个IEnumerable,并且行是惰性计算的,因此只会加载第一行两次
ReadLines和ReadAllLines方法的区别如下:使用ReadLines时,可以在返回整个集合之前开始枚举字符串集合;使用ReadAllLines时,必须等待返回整个字符串数组,然后才能访问该数组。因此,当您处理非常大的文件时,ReadLines会更加高效
您可以使用ReadLines方法执行以下操作:
对文件执行LINQ to Objects查询以获得其行的过滤集
使用file.writeAllines(字符串, 方法,或使用file.AppendAllLines(字符串, IEnumerable)方法
创建一个立即填充的集合实例,该集合的构造函数采用IEnumerable字符串集合,如IList或队列
此方法使用UTF8作为编码值
如果您还有任何疑问,请查看以下答案:
使用CsvHelper软件包的第二个解决方案
首先,安装这个nuget包
PM> Install-Package CsvHelper
对于给定的CSV,我们应该创建一个类来表示它
CSV文件
Name;Age;Birthdate;Working
Alberto Monteiro;25;01/01/1990;true
Other Person;5;01/01/2010;false
班级模式是
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime Birthdate { get; set; }
public bool Working { get; set; }
}
现在让我们使用CsvReader来构建数据表
public DataTable readCSV(string filePath)
{
var dt = new DataTable();
var csv = new CsvReader(new StreamReader(filePath));
// Creating the columns
typeof(Person).GetProperties().Select(p => p.Name).ToList().ForEach(x => dt.Columns.Add(x));
// Adding the rows
csv.GetRecords<Person>().ToList.ForEach(line => dt.Rows.Add(line.Name, line.Age, line.Birthdate, line.Working));
return dt;
}
公共数据表readCSV(字符串文件路径)
{
var dt=新数据表();
var csv=新的CsvReader(新的StreamReader(filePath));
//创建列
typeof(Person).GetProperties().Select(p=>p.Name).ToList().ForEach(x=>dt.Columns.Add(x));
//添加行
csv.GetRecords().ToList.ForEach(line=>dt.Rows.Add(line.Name、line.Age、line.Birthdate、line.Working));
返回dt;
}
要在DataTable e中创建列,请使用一些反射,然后使用GetRecords方法在DataTable中添加行,使用Microsoft.VisualBasic.FileIO代码> 我建议如下。它至少应该有这样的优势“;”字段中的内容将得到正确处理,并且不受特定csv格式的限制
public class CsvImport
{
public static DataTable NewDataTable(string fileName, string delimiters, bool firstRowContainsFieldNames = true)
{
DataTable result = new DataTable();
using (TextFieldParser tfp = new TextFieldParser(fileName))
{
tfp.SetDelimiters(delimiters);
// Get Some Column Names
if (!tfp.EndOfData)
{
string[] fields = tfp.ReadFields();
for (int i = 0; i < fields.Count(); i++)
{
if (firstRowContainsFieldNames)
result.Columns.Add(fields[i]);
else
result.Columns.Add("Col" + i);
}
// If first line is data then add it
if (!firstRowContainsFieldNames)
result.Rows.Add(fields);
}
// Get Remaining Rows
while (!tfp.EndOfData)
result.Rows.Add(tfp.ReadFields());
}
return result;
}
}
公共类CsvImport
{
公共静态数据表NewDataTable(字符串文件名、字符串分隔符、bool firstRowContainsFieldNames=true)
{
DataTable结果=新DataTable();
使用(TextFieldParser tfp=新的TextFieldParser(文件名))
{
tfp.SetDelimiters(分隔符);
//获取一些列名
如果(!tfp.EndOfData)
{
string[]fields=tfp.ReadFields();
对于(int i=0;i
CsvHelper的作者在库中构建功能。
代码变得简单:
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.CurrentCulture))
{
// Do any configuration to `CsvReader` before creating CsvDataReader.
using (var dr = new CsvDataReader(csv))
{
var dt = new DataTable();
dt.Load(dr);
}
}
CultureInfo.CurrentCulture用于确定默认分隔符,如果要读取Excel保存的csv,则需要该分隔符。您似乎在为每个标记向表中添加一行,而不是为文件中的每一行。另外,您可以将数据绑定到
DataGrid
,而无需迭代itDestic。您看到我的答案了吗?有什么反馈吗?我原以为你需要空条目。还是我读错了?@HughJones下面的字符串abc;abc;;abc
如果按拆分
您将有4个条目=>abc | abc | | abc
,如果您不想有空条目,请使用StringSplitOptions.RemoveEmptyEntries。所以在本例中,我将更改答案,在行中我想要空条目,但在标题中,我不需要。在这两个行中,我都会想。如果标题中的字段数与行中的字段数不匹配,则不希望出现这种情况。很好的解决方案,+1对File.ReadLines的两次调用不会读取整个文件两次吗?使用反射的性能损失是什么?@aardila File.ReadLines不会读取所有行,它返回一个IEnumerable,并且行是延迟计算的,因此只会加载第一行两次。Will更改了我的答案来解释这一点。谢谢,这看起来是一种可靠的方法,但我在哪里可以找到VisualBasic.FileIO命名空间?在您的project@Destic-关于可靠性;首先有一个基本假设,即加载的csv文件是有效的。您的方法工作得很好。我只是在结尾编辑了while,因为我想让datatable包含行作为结果<代码>w
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader, CultureInfo.CurrentCulture))
{
// Do any configuration to `CsvReader` before creating CsvDataReader.
using (var dr = new CsvDataReader(csv))
{
var dt = new DataTable();
dt.Load(dr);
}
}