我知道如何阅读和显示.csv文件的一行。现在我想解析该文件,将其内容存储在数组中,并将这些数组用作我创建的某些类的值。
我想学习如何。
以下是一个例子:
basketball,2011/01/28,Rockets,Blazers,98,99
baseball,2011/08/22,Yankees,Redsox,4,3
如您所见,每个字段都以逗号分隔。我创建了Basketball.cs和Baseball类,它是Sport.cs类的扩展,它有以下字段:
private string sport;
private string date;
private string team1;
private string team2;
private string score;
我理解这是简单的,并且有更好的方法来存储这些信息,即为每个团队创建类,使日期成为DateType数据类型,并且更多相同但我想知道如何输入这个信息进入课堂。
我认为这与getter和setter有关...我也读过字典和集合,但我想通过将它们全部存储在数组中来开始简单...(如果这样做的话)感觉......随意纠正我。)
这是我到目前为止所拥有的。它所做的就是阅读csv并在控制台上鹦鹉学舌:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Assign01
{
class Program
{
static void Main(string[] args)
{
string line;
FileStream aFile = new FileStream("../../sportsResults.csv", FileMode.Open);
StreamReader sr = new StreamReader(aFile);
// read data in line by line
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
line = sr.ReadLine();
}
sr.Close();
}
}
}
非常感谢帮助。
答案 0 :(得分:6)
创建数组以保存信息不是一个好主意,因为您不知道输入文件中将包含多少行。你的数组的初始大小是多少?我建议你使用例如通用列表来保存信息(例如List<>)。
您还可以向接受数组的Sport Class添加构造函数(如上面的答案中所述的分割操作的结果。
此外,您可以在setter中提供一些转换
public class Sport
{
private string sport;
private DateTime date;
private string team1;
private string team2;
private string score;
public Sport(string[] csvArray)
{
this.sport = csvArray[0];
this.team1 = csvArray[2];
this.team2 = csvArray[3];
this.date = Convert.ToDateTime(csvArray[1]);
this.score = String.Format("{0}-{1}", csvArray[4], csvArray[5]);
}
为了简单起见,我编写了转换方法,但请记住,除非您确定DateField始终包含有效日期且分数始终包含数字值,否则这也不是一种非常安全的方法。您可以尝试其他更安全的方法,如tryParse或一些异常处理。
我很诚实,它必须补充说上述解决方案很简单(根据要求),在概念层面我会建议反对它。将属性和csv文件之间的映射逻辑放在类中会使体育类过于依赖文件本身,从而减少可重用性。然后,文件结构中的任何后续更改都应反映在您的课程中,并且通常会被忽略。因此,将你的“映射& amp;转换“主程序中的逻辑,尽可能保持你的班级干净
(通过将其格式化为2个字符串和连字符来更改您的"分数"问题)
答案 1 :(得分:6)
将sting拆分为数组以获取数据可能容易出错且速度慢。尝试使用OLE数据提供程序读取CSV,就好像它是SQL数据库中的表一样,这样就可以使用WHERE子句来过滤结果。
App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="csv" providerName="System.Data.OleDb" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source='C:\CsvFolder\';Extended Properties='text;HDR=Yes;FMT=Delimited';" />
</connectionStrings>
</configuration>
program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Configuration;
using System.Data;
using System.Data.Common;
namespace CsvImport
{
class Stat
{
public string Sport { get; set; }
public DateTime Date { get; set; }
public string TeamOne { get; set; }
public string TeamTwo { get; set; }
public int Score { get; set; }
}
class Program
{
static void Main(string[] args)
{
ConnectionStringSettings csv = ConfigurationManager.ConnectionStrings["csv"];
List stats = new List();
using (OleDbConnection cn = new OleDbConnection(csv.ConnectionString))
{
cn.Open();
using (OleDbCommand cmd = cn.CreateCommand())
{
cmd.CommandText = "SELECT * FROM [Stats.csv]";
cmd.CommandType = CommandType.Text;
using (OleDbDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
int fieldSport = reader.GetOrdinal("sport");
int fieldDate = reader.GetOrdinal("date");
int fieldTeamOne = reader.GetOrdinal("teamone");
int fieldTeamTwo = reader.GetOrdinal("teamtwo");
int fieldScore = reader.GetOrdinal("score");
foreach (DbDataRecord record in reader)
{
stats.Add(new Stat
{
Sport = record.GetString(fieldSport),
Date = record.GetDateTime(fieldDate),
TeamOne = record.GetString(fieldTeamOne),
TeamTwo = record.GetString(fieldTeamTwo),
Score = record.GetInt32(fieldScore)
});
}
}
}
}
foreach (Stat stat in stats)
{
Console.WriteLine("Sport: {0}", stat.Sport);
}
}
}
}
修改
我忘了展示csv的外观:)
stats.csv sport,date,teamone,teamtwo,score basketball,28/01/2011,Rockets,Blazers,98 baseball,22/08/2011,Yankees,Redsox,4
答案 2 :(得分:3)
虽然有很多库可以让csv阅读变得简单(参见:here),但现在你需要做的就是分割它。
String[] csvFields = line.Split(",");
现在将每个字段分配给相应的成员
sport = csvFields[0];
date = csvFields[1];
//and so on
但是,每次读取新行时都会覆盖这些值,因此您需要将值打包到类中,并将该类的实例保存到列表中。
答案 3 :(得分:1)
// use "Microsoft.VisualBasic.dll"
using System;
using Microsoft.VisualBasic.FileIO;
class Program {
static void Main(string[] args){
using(var csvReader = new TextFieldParser(@"sportsResults.csv")){
csvReader.SetDelimiters(new string[] {","});
string [] fields;
while(!csvReader.EndOfData){
fields = csvReader.ReadFields();
Console.WriteLine(String.Join(",",fields));//replace make instance
}
}
}
}
答案 4 :(得分:0)
以下是新手和引人注目的解决方案,大多数新手喜欢尝试和错误 请不要忘记在参考文献中添加System.Core.dll 在.cs文件中导入名称空间:using System.Linq;
也许添加迭代器将是更好的代码
private static IEnumerable<String> GetDataPerLines()
{
FileStream aFile = new FileStream("sportsResults.csv",FileMode.Open);
StreamReader sr = new StreamReader(aFile);
while ((line = sr.ReadLine()) != null)
{
yield return line;
}
sr.Close();
}
static void Main(string[] args)
{
var query = from data in GetDataPerLines()
let splitChr = data.Split(",".ToCharArray())
select new Sport
{
sport = splitChr[0],
date = splitChr[1],.. and so on
}
foreach (var item in query)
{
Console.Writeline(" Sport = {0}, in date when {1}",item.sport,item.date);
}
}
也许是这样,上面的示例是使用yield创建自己的迭代(请查看MSDN文档)并根据您的字符串创建集合。
如果我写代码错误,请告诉我,因为我没有;当我写答案时,我有Visual Studio。 根据您的了解,像“Sport []”这样的数组一维将转换为CLR IEnumerable
答案 5 :(得分:0)
对于一个有弹性,快速且省力的解决方案,您可以使用CsvHelper来处理很多代码和边缘情况,并且具有很好的documentation
如果您的csv具有以下标头:
sport,date,team 1,team 2,score 1,score 2
basketball,2011/01/28,Rockets,Blazers,98,99
baseball,2011/08/22,Yankees,Redsox,4,3
您可以在类中添加属性,以将字段名称映射到您的类名称,如下所示:
public class SportStats
{
[Name("sport")]
public string Sport { get; set; }
[Name("date")]
public DateTime Date { get; set; }
[Name("team 1")]
public string TeamOne { get; set; }
[Name("team 2")]
public string TeamTwo { get; set; }
[Name("score 1")]
public int ScoreOne { get; set; }
[Name("score 2")]
public int ScoreTwo { get; set; }
}
然后像这样调用:
List<SportStats> records;
using (var reader = new StreamReader(@".\stats.csv"))
using (var csv = new CsvReader(reader))
{
records = csv.GetRecords<SportStats>().ToList();
}
如果您的csv没有这样的标头:
basketball,2011/01/28,Rockets,Blazers,98,99
baseball,2011/08/22,Yankees,Redsox,4,3
您可以将属性添加到类中,并通常按如下所示的位置映射到CSV:
public class SportStats
{
[Index(0)]
public string Sport { get; set; }
[Index(1)]
public DateTime Date { get; set; }
[Index(2)]
public string TeamOne { get; set; }
[Index(3)]
public string TeamTwo { get; set; }
[Index(4)]
public int ScoreOne { get; set; }
[Index(5)]
public int ScoreTwo { get; set; }
}
然后像这样调用:
List<SportStats> records;
using (var reader = new StreamReader(@".\stats.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.HasHeaderRecord = false;
records = csv.GetRecords<SportStats>().ToList();
}
答案 6 :(得分:0)
Linq对此也有解决方案,您可以将输出定义为列表或数组。在下面的示例中,有一个类作为数据和数据类型的定义。
var modelData = File.ReadAllLines(dataFile)
.Skip(1)
.Select(x => x.Split(','))
.Select(dataRow => new TestModel
{
Column1 = dataRow[0],
Column2 = dataRow[1],
Column3 = dataRow[2],
Column4 = dataRow[3]
}).ToList(); // Or you can use .ToArray()