读取csv文件并将数据存储在二维对象数组中

时间:2015-07-15 19:48:49

标签: c# csv object

首先,如果csv文件(例如:日期和价格)包含一些空单元格,当我尝试将数据存储在列表中时,如何解决此问题?

其次,一旦两个列表没问题,我想知道如何创建一个二维对象,例如PriceByDate[100,2]Date[100,0],Price[100,1]),它可以存储来自csv文件的数据。

提前致谢

这是我的代码:(不工作)

var reader = new StreamReader(File.OpenRead(@"filenames"));

List<string> Dates = new List<string>();
List<string> Prices = new List<double>();
while (!reader.EndOfStream)
{
    var line = reader.ReadLine();
    var values = line.Split(';');

    listA.Add(values[0]);
    listB.Add(values[1]);
} 

DateTime[] s = Convert.ToDateTime(ListA.toArray());
double[] o = ListB.toArray();
object[,] PriceByDate = new object[,]{{s},{o}};

2 个答案:

答案 0 :(得分:1)

首先,建议:

我建议使用免费的第三方CSV库,而不是重新发明轮子,除非有某种原因你不能。

http://joshclose.github.io/CsvHelper/

现在,答案是:

听起来你的问题是如何处理空单元格。首先,您需要确保每一行都是正确的长度,在CSV中,您至少会在每个单元格之间划分界限,即使它们是空的。 (注意:我在没有IDE的情况下长时间编写了所有这些代码,它可能不会按原样编译,可能会有错误。)

var line = reader.ReadLine();
var values = line.Split(';');
if (values.Count != numColumnsExpected)
{
    throw new System.Exception("Expected " + numColumnsExpected + " columns, only found " + values.Count + " columns for a row.");
}

每列应具有预期类型,如果您想要彻底,可以为每列提供验证和处理功能。您可以将列号映射到字典中的函数。

private void ProcessorDelegate(string value);

Dictionary<int, ProcessorDelegate> m_processorMethods = new Dictionary<int, ProcessorDelegate>
{
    { 0, DateProcessor },
    { 1, PriceProcessor },
}

private void DateProcessor(string value)
{
    // Make sure 'value' is a date
    DateTime date;
    if (!DateTime.TryParse(value, out date))
    {
        // If this field is required you could throw an exception here, or output a console error.
        // This is the point at which you could check if 'value' was null or empty.

        return;
    }

    // 'value' was a date, so add it to the DateTime[] array.
    Dates.Add(date);
}

int numColumnsExpected = 6;

var Dates = new List<string>();
var Prices = new List<double>();

while (!reader.EndOfStream)
{
    var line = reader.ReadLine();
    var values = line.Split(';');

    if (values.Count != numColumnsExpected)
    {
         throw new System.Exception("Expected " + numColumnsExpected + " columns, only found " + values.Count + " columns for a row.");
    }

    // Sanity check, you must have a processor for each column
    if (values.Count > m_processorMethods.Count)
    {
         throw new System.Exception("Expected " + numColumnsExpected + " processor methods, only found " + m_processorMethods.Count);
    }

    for (int i = 0; i < values.Count; ++i)
    {
        // Pass the value for a column to the processor that handles
        // data for that column.
        m_processorMethods[i](values[i]);
    }
} 
   DateTime[] s=Convert.ToDateTime(ListA.toArray());
   double[] o=ListB.toArray();
   object[,] PriceByDate=new object[,]{{s},{o}} ;
}

警告:

将数据存储在一系列2D数组中,这些数组应该通过索引相互映射,非常脆弱。即使将其存储在2D对象数组中也不是非常有用,因为您需要转换这些对象以使用它们,并且您需要知道每列的顺序是什么数据类型无论如何要施放它们。

我强烈建议创建一个包含行数据的类。在该课程中,您可以存储日期,价格以及您需要的任何其他数据。然后你可以只有一个List或这些对象的数组,每个对象代表一行。

public class RowObject
{
    public DateTime date;
    public string price;
}

List<RowObject> m_rowData;

// A delegate that can take the RowObject
private void ProcessorDelegate(string value, RowObject currentRow);

// Pass in the RowObject to your processors
// The processor updates the RowObject with the processed information.
private void DateProcessor(string value, RowObject currentRow)
{
    // Make sure 'value' is a date
    DateTime date;
    if (!DateTime.TryParse(value, out date))
    {
        // If this field is required you could throw an exception here, or output a console error.
        // This is the point at which you could check if 'value' was null or empty.

        return;
    }

    // 'value' was a date, so set this row's date
    currentRow.date = date;
}

现在,一行的所有数据都很好地捆绑在一起,如果有空单元格,则该行的RowObject缺少该数据。您可以通过向RowObject添加验证方法来轻松验证行。

public class RowObject
{
    public DateTime date;
    public string price;

    public bool IsValid()
    {
        if (date == null)
        {
            // Maybe output a warning to console here
            return false;
        }

        if (string.IsNullOrEmpty(price))
        {
            // Maybe output a warning to console here
            return false;
        }

        return true;
    }
}

<强>最后

让我重申一下这一点,重新发明轮子,如果你使用CSVHelper库,我提供了一个链接,那么你不需要大部分代码。

答案 1 :(得分:1)

本文介绍如何使用ADO.net读取CSV文件。这很简单。使用此方法,您的日期和价格信息将在已配对的行/记录对象上。

文章:Reading CSV files in ADO.NET

如果您使用上述文章解决方案,您需要做的就是对记录字段进行简单的string.IsNullOrEmpty测试。如果函数返回true,则可以跳过行/记录。

我不确定这是否就像你在“2-D”对象中所寻找的那样。如果您需要在代码中创建一个对象,以便在从记录中读取数据后保存数据,我会使用类似的东西。另外,您可能还想使用小数来保存货币值。

public class PriceAndDate
{
    public DateTime Date {get;set;}
    public Decimal Price {get;set;}
}

List<PriceAndDate> priceAndDate = new List<PriceAndDate>();