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);
        }

StreamReader跳过Null或空白行的最佳方式

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类。找到一个更有意义的对象,您可以将此数据与之关联。


*免责声明:我是该解析器的作者