提问者:小点点

DataTable的行与列混淆


我正在学习一个用C#语言编写的库存管理系统的教程。

最初的csv文件是一个股票列表,其中包含四个类别:

Item Code, Item Description, Item Count, OnOrder

原始csv文件:

在教程中,代码正在生成一个DataTable对象,该对象将在应用程序中的GridView演示中使用。

下面是代码:

DataTable dataTable = new DataTable();
            
dataTable.Columns.Add("Item Code");
dataTable.Columns.Add("Item Description");
dataTable.Columns.Add("Current Count");
dataTable.Columns.Add("On Order");

string CSV_FilePath = "C:/Users/xxxxx/Desktop/stocklist.csv";

StreamReader streamReader = new StreamReader(CSV_FilePath);

string[] rawData = new string[File.ReadAllLines(CSV_FilePath).Length];
rawData = streamReader.ReadLine().Split(',');
            
while(!streamReader.EndOfStream)
{
    rawData = streamReader.ReadLine().Split(',');
    dataTable.Rows.Add(rawData[0], rawData[1], rawData[2], rawData[3]);
}

dataGridView1.DataSource = dataTable;

我假设rawdata=StreamReader.ReadLine().split(',');将文件拆分为如下数组对象:

["A0001", "Horse on Wheels","5","No"]
["A0002","Elephant on Wheels","2","No"]

在while循环中,它通过每一行(每个数组)进行读写,并将每个rawdata[x]分配到相应的列中。

这样理解这个代码片段是正确的吗?提前谢谢你。

另一个问题是,我为什么要跑

rawData = streamReader.ReadLine().Split(',');

在while循环中?

提前谢谢你。


共1个答案

匿名用户

您的代码实际上应该如下所示:

DataTable dataTable = new DataTable();

dataTable.Columns.Add("Item Code");
dataTable.Columns.Add("Item Description");
dataTable.Columns.Add("Current Count");
dataTable.Columns.Add("On Order");

string CSV_FilePath = "C:/Users/xxxxx/Desktop/stocklist.csv";

using(StreamReader streamReader = new StreamReader(CSV_FilePath))
{
    // Skip the header row
    streamReader.ReadLine();
    
    while(!streamReader.EndOfStream)
    {
        string[] rawData = streamReader.ReadLine().Split(','); // read a row and split it into cells
        dataTable.Rows.Add(rawData[0], rawData[1], rawData[2], rawData[3]); // add the elements from each cell as a row in the datatable
    }
}

dataGridView1.DataSource = dataTable;

我所做的更改:

  • 我们在StreamReader周围添加了一个using块,以确保文件句柄仅在需要读取文件时打开。
  • 我们现在只读取文件一次,而不是两次。
  • 因为我们只需要while循环范围中的rawdata,所以我将它移到循环中。

解释问题:

下面一行读取整个文件,然后计算其中有多少行。利用这些信息,我们初始化一个数组,其位置与文件中的行数一样多。这意味着对于500行文件,您可以访问位置RawData[0]RawData[1],...RawData[499]

string[] rawData = new string[File.ReadAllLines(CSV_FilePath).Length];

对于下一行,您将丢弃该数组,取而代之的是文件顶部的单元格(标题):

rawData = streamReader.ReadLine().Split(',');

这一行声明“从文件中读取单行,并按逗号拆分”。然后将该结果分配给rawdata,替换其旧值。因此,在循环中再次需要该文件的原因是,您感兴趣的不仅仅是文件的第一行。

最后,循环遍历文件中的每一行,并用该行中的单元格替换rawdata。最后,将每一行添加到DataTable:

rawData = streamReader.ReadLine().Split(',');
dataTable.Rows.Add(rawData[0], rawData[1], rawData[2], rawData[3]);

请注意,file.ReadAllLines(。。。)将整个文件作为字符串数组读入内存。您还使用StreamReader逐行读取文件,这意味着您将两次读取整个文件。这不是非常有效,您应该尽可能避免这种情况。在这种情况下,我们根本不需要这么做。

还要注意,您读取CSV文件的方法相当幼稚。根据创建它们所用的软件,有些CSV文件的单元格跨越文件中的多行,有些包含带引号的文本部分,有时那些带引号的部分包含逗号,这会使您的拆分代码脱节。您的代码也没有处理文件格式错误的可能性,例如一行的单元格比预期的少,或者文件末尾有一个空行。一般来说,最好使用专用的CSV解析器,比如CsvHelper,而不是尝试滚动自己的解析器。