StreamReader跳过Null或空白行的最佳方式
本文关键字:最佳 方式 空白 跳过 Null StreamReader | 更新日期: 2023-09-27 18:07:57
在搜索和尝试了不同的方法之后,我发现我要么对我编写代码的方式不满意,要么它不适合我。我是编程新手,所以我的理解有限。请记住答案。
我想逐行读取。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);
}
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());
}
只要检查value.Length == 6
,这样它就会跳过那些不包含足够数据的行
使用专用的CSV解析器,例如这里提供的EasyCSV类*:
https://github.com/jcoehoorn/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
类。找到一个更有意义的对象,您可以将此数据与之关联。
*免责声明:我是该解析器的作者