在搜索并尝试了我发现的不同方式之后,我或者对我编写代码的方式感到满意,或者它对我来说并不适合。我是编程新手,所以我的理解是有限的。请记住答案。
我想逐行读取.csv文件并跳过空白行。用我想要放入对象列表的行的内容。我有一切工作,除了跳绳部分。此外,任何有关改进我的代码的任何部分的反馈都是受欢迎的。我喜欢建设性的批评。
public void CardaxCsvFileReader()
{
string cardaxCsvPath = (@"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
try
{
using (System.IO.StreamReader cardaxSR =
new System.IO.StreamReader(System.IO.File.OpenRead(cardaxCsvPath)))
{
string line = "";
string[] value = line.Split(',');
while (!cardaxSR.EndOfStream)
{ // this commented out part is what I would like to work but doesn't seem to work.
line = cardaxSR.ReadLine();//.Skip(1).Where(item => !String.IsNullOrWhiteSpace(item));
value = line.Split(',');
if (line != ",,,,,") // using this as temp to skip the line because the above commented out part doesn't work.
{
CardaxDataObject cardaxCsvTest2 = new CardaxDataObject();
cardaxCsvTest2.EventID = Convert.ToInt32(value[0]);
cardaxCsvTest2.FTItemID = Convert.ToInt32(value[1]);
cardaxCsvTest2.PayrollNumber = Convert.ToInt32(value[2]);
cardaxCsvTest2.EventDateTime = Convert.ToDateTime(value[3]);
cardaxCsvTest2.CardholderFirstName = value[4];
cardaxCsvTest2.CardholderLastName = value[5];
Globals.CardaxQueryResult.Add(cardaxCsvTest2);
}
}
}
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
答案 0 :(得分:0)
只需检查是否value.Length == 6
,这样就会跳过没有足够数据列的行
答案 1 :(得分:0)
<强> EDITED 强>
如果您的行不是真正空白且包含逗号,则可以使用RemoveEmptyEntries选项进行拆分,然后检查列数。
while (!cardaxSR.EndOfStream)
{ // this commented out part is what I would like to work but doesn't seem to work.
line = cardaxSR.ReadLine();//.Skip(1).Where(item => !String.IsNullOrWhiteSpace(item));
value = line.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries); // <-- Remove empty columns while splitting. It has a side-effect: Any record with just a single blank column will also get discarded by the if that follows.
if (value.length < 6)
continue;
CardaxDataObject cardaxCsvTest2 = new CardaxDataObject();
cardaxCsvTest2.EventID = Convert.ToInt32(value[0]);
cardaxCsvTest2.FTItemID = Convert.ToInt32(value[1]);
cardaxCsvTest2.PayrollNumber = Convert.ToInt32(value[2]);
cardaxCsvTest2.EventDateTime = Convert.ToDateTime(value[3]);
cardaxCsvTest2.CardholderFirstName = value[4];
cardaxCsvTest2.CardholderLastName = value[5];
Globals.CardaxQueryResult.Add(cardaxCsvTest2);
}
我的另一个改进反馈:当您捕获异常时,除了自定义错误行之外,最好记录异常。自定义错误行可能对网站用户说好,但作为运行某些服务的开发人员,您会欣赏实际的异常堆栈跟踪。它将帮助您更轻松地调试错误。
catch (Exception ex)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\".\r\n Exception: {1}", cardaxCsvPath, ex.ToString());
}
答案 2 :(得分:0)
使用专用CSV解析器,例如此处提供的EasyCSV类 * :
public void CardaxCsvFileReader()
{
try
{
string cardaxCsvPath = (@"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
Globals.CardaxQueryResult =
EasyCSV.FromFile(cardaxCsvPath)
.Where(r => r.Any(c => !string.IsNullOrEmpty(c)))
.Select(r => CardaxDataObject() {
cardaxCsvTest2.EventID = int.Parse(r[0]),
cardaxCsvTest2.FTItemID = int.Parse(r[1]),
cardaxCsvTest2.PayrollNumber = int.Parse(r[2]),
cardaxCsvTest2.EventDateTime = DateTinme.Parse(r[3]),
cardaxCsvTest2.CardholderFirstName = r[4],
cardaxCsvTest2.CardholderLastName = r[5]
}).ToList();
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
}
我还建议重新思考如何构建它。以下代码是更好的做法:
public IEnumerable<CardaxDataObject> ReadCardaxCsvFile(string filename)
{
//no try block at this level. Catch that in the method that calls this method
return EasyCSV.FromFile(cardaxCsvPath)
.Where(r => r.Any(c => !string.IsNullOrEmpty(c)))
// You may want to put a try/catch inside the `Select()` projection, though.
// It would allow you continue if you fail to parse an individual record
.Select(r => CardaxDataObject() {
cardaxCsvTest2.EventID = int.Parse(r[0]),
cardaxCsvTest2.FTItemID = int.Parse(r[1]),
cardaxCsvTest2.PayrollNumber = int.Parse(r[2]),
cardaxCsvTest2.EventDateTime = DateTinme.Parse(r[3]),
cardaxCsvTest2.CardholderFirstName = r[4],
cardaxCsvTest2.CardholderLastName = r[5]
});
}
突然间,这个方法归结为一个陈述(尽管是一个很长的陈述)。像这样的代码更好,因为它更强大,原因有三:它不仅限于使用一个输入文件,它不仅限于将它的输出发送到一个位置,而且不受限制只有一种方法来处理错误。你会这样称呼它:
try
{
string cardaxCsvPath = (@"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
Globals.CardaxQueryResult = ReadCardaxCsvFile(cardaxCsvPath).ToList();
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
或者像这样:
try
{
string cardaxCsvPath = (@"C:\Cardax2WkbTest\Cardax\CardaxTable.csv");
foreach (var result in ReadCardaxCsvFile(cardaxCsvPath))
{
Globals.CardaxQueryResult.Add(result);
}
}
catch (Exception)
{
myLog.Error("Unable to open/read Cardax simulated punch csv file! " +
"File already open or does not exist: \"{0}\"", cardaxCsvPath);
}
我还建议不要使用像这样的Globals
类。找到一个更有意义的对象,您可以使用该对象关联此数据。
*免责声明:我是该解析器的作者