[英]Read CSV file in DataGridView
我想将 csv 文件读入 Datagridview。 我想要一个类和一个函数,它可以像这样读取 csv:
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);
}
结果是-> 创建了行,但单元格中没有数据!
public DataTable readCSV(string filePath)
{
var dt = new DataTable();
// Creating the columns
File.ReadLines(filePath).Take(1)
.SelectMany(x => x.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
.ToList()
.ForEach(x => dt.Columns.Add(x.Trim()));
// Adding the rows
File.ReadLines(filePath).Skip(1)
.Select(x => x.Split(';'))
.ToList()
.ForEach(line => dt.Rows.Add(line));
return dt;
}
在使用 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,但现在我们 Skip(1),这会跳过标题行,现在我们将使用 Select,创建一个Collection<Collection<string>>
,然后再次调用 ToList,最后调用 ForEach 在 DataTable 中添加行。 File.ReadLines 在 .NET 4.0 中可用。
Obs.: File.ReadLines不会读取所有行,它返回一个 IEnumerable,并且行是惰性评估的,因此只会加载第一行两次。
ReadLines 和 ReadAllLines 方法的区别如下: 使用 ReadLines 时,可以在返回整个集合之前开始枚举字符串集合; 使用 ReadAllLines 时,必须等待返回整个字符串数组才能访问该数组。 因此,当您处理非常大的文件时,ReadLines 会更有效率。
您可以使用 ReadLines 方法执行以下操作:
对文件执行 LINQ to Objects 查询以获取过滤后的行集。
使用 File.WriteAllLines(String, IEnumerable) 方法将返回的行集合写入文件,或使用 File.AppendAllLines(String, IEnumerable) 方法将它们附加到现有文件。
创建一个立即填充的集合实例,该实例采用 IEnumerable 字符串集合作为其构造函数,例如 IList 或 Queue。
此方法使用 UTF8 作为编码值。
如果您仍有任何疑问,请查看以下答案: File.ReadLines() 和 File.ReadAllLines() 有什么区别?
首先,安装这个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 来构建 DataTable
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;
}
要在 DataTable e 中创建列,请使用一些反射,然后使用 GetRecords 方法在 DataTabble 中添加行
using 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;
}
}
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,则需要。
我遇到了同样的问题,但我找到了一种以我自己的方式使用@Alberto Monteiro的答案的方法......
我的 CSV 文件没有“First-Line-Column-Header”,我个人出于某些原因没有将它们放在那里,所以这是文件示例
1,john doe,j.doe,john.doe@company.net
2,jane doe,j.doe,jane.doe@company.net
所以你的想法对吗?
现在,我将手动将Columns
添加到DataTable
。 而且我将使用Tasks
异步执行此操作。 并且只需使用foreach
循环使用以下函数将值添加到DataTable.Rows
中:
public Task<DataTable> ImportFromCSVFileAsync(string filePath)
{
return Task.Run(() =>
{
DataTable dt = new DataTable();
dt.Columns.Add("Index");
dt.Columns.Add("Full Name");
dt.Columns.Add("User Name");
dt.Columns.Add("Email Address");
// splitting the values using Split() command
foreach(var srLine in File.ReadAllLines(filePath))
{
dt.Rows.Add(srLine.Split(','));
}
return dt;
});
}
现在调用函数我只需ButtonClick
来完成这项工作
private async void ImportToGrid_STRBTN_Click(object sender, EventArgs e)
{
// Handling UI objects
// Best idea for me was to put everything a Panel and Disable it while waiting
// and after the job is done Enabling it
// and using a toolstrip docked to bottom outside of the panel to show progress using a
// progressBar and setting its style to Marquee
panel1.Enabled = false;
progressbar1.Visible = true;
try
{
DataTable dt = await ImportFromCSVFileAsync(@"c:\myfile.txt");
if (dt.Rows.Count > 0)
{
Datagridview1.DataSource = null; // To clear the previous data before adding the new ones
Datagridview1.DataSource = dt;
}
}
catch (Exception ex)
{
MessagBox.Show(ex.Message, "Error");
}
progressbar1.Visible = false;
panel1.Enabled = true;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.