【问题标题】:IndexOutOfRange Exception when working with DataTable使用 DataTable 时出现 IndexOutOfRange 异常
【发布时间】:2016-08-12 09:26:29
【问题描述】:

我正在使用 StreamReader 访问 CSV 文本文件并将所有行读取到 DataTable。

public static DataTable ConvertToDataTable(string filePath, int numberOfColumns)
    {
        DataTable tbl = new DataTable();

        for (int col = 0; col < numberOfColumns; col++)
            tbl.Columns.Add(new DataColumn("Column" + (col + 1).ToString()));

        string line;
        System.IO.StreamReader file = new StreamReader("C:/ProgramData/3CX/Instance1/Data/Logs/CDRLogs/cdr.log");

        while ((line = file.ReadLine()) != null)
        {
            var cols = line.Split(',');
            DataRow dr = tbl.NewRow();
            for (int cIndex = 0; cIndex < cols.Length + 1; cIndex++)
            {
                dr[cIndex] = cols[cIndex];
            }
            tbl.Rows.Add(dr);
        }

将所有 CSV 行添加到 DataTable 后,我想遍历这些行并根据条件删除不需要的行。

DataTable dt = ConvertToDataTable("C:/ProgramData/3CX/Instance1/Data/Logs/CDRLogs", 4);

        for (int i = 0; i < dt.Rows.Count; i++)
        {
            string duration = dt.Rows[i][1].ToString();
            if (duration == "")
            {
                dt.Rows[i].Delete();
            }
            Console.WriteLine(i.ToString() + dt.Rows[i][1].ToString());
        }

这运行得很好,直到我到达最后一行,它似乎在循环一个不存在的行。

有人知道为什么吗?任何和所有的帮助将不胜感激!

【问题讨论】:

  • 您到底在哪里遇到了异常?也许最后一行不包含第二列? dt.Rows[i][1]
  • 根据经验,永远不要删除您正在迭代的集合的元素,即使使用 for 循环,您也需要注意(如@Adimeus 建议的那样向后迭代)。在您的代码中,如果您删除最后一行,则下一行您尝试访问不再存在的 Rows[i]。即使它不是最后一行,Rows[i] 也指的是您删除的行之后的行。我想不是你想在控制台上写的。
  • &lt; cols.Length + 1 看起来也很可疑,不是吗?

标签: c# .net datatable


【解决方案1】:

您可以向后遍历行以保持索引不变。

for(int i = dt.Rows.Count - 1; i >= 0; i--)
{
   dt.Rows[i].Delete();
}

【讨论】:

    【解决方案2】:

    删除时,循环向后,而不是:

    for (int i = 0; i < dt.Rows.Count; i++)
    {
      ...    
      dt.Rows[i].Delete();
      ... 
    }
    

    for (int i = dt.Rows.Count - 1; i >= 0 ; --i)
    {
        string duration = dt.Rows[i][1].ToString();
    
        if (duration == "")
        {
            dt.Rows[i].Delete();
        }
        Console.WriteLine(i.ToString() + dt.Rows[i][1].ToString());
    }
    

    如果您出于任何原因必须循环forward,请将循环修改为

    for (int i = 0; i < dt.Rows.Count; ) // do not increment here
    {
        string duration = dt.Rows[i][1].ToString();
    
        if (duration == "")
        {
            dt.Rows[i].Delete();
        }
        else
            i += 1; // ... but increment here 
    
        Console.WriteLine(i.ToString() + dt.Rows[i][1].ToString());
    }
    

    【讨论】:

      【解决方案3】:

      删除行时,不应设置 i=i+1 ,因为数量或行数减少了

              int i = 0; 
              while(i < dt.Rows.Count)
              {
                  string duration = dt.Rows[i][1].ToString();
                  if (duration == "")
                  {
                      dt.Rows[i].Delete();
                  }
                  else
                  {i++;}
                  Console.WriteLine(i.ToString() + dt.Rows[i][1].ToString());
              }
      

      【讨论】:

        【解决方案4】:

        在循环结束时增加i

        for (int i = 0; i < dt.Rows.Count; )
        {
            string duration = dt.Rows[i][1].ToString();
            if (duration == "")
            {
                dt.Rows[i].Delete();
            }
            else
            {
                i++;
            }
            Console.WriteLine(i.ToString() + dt.Rows[i][1].ToString());
        }
        

        【讨论】:

          【解决方案5】:

          当我必须从我正在迭代的集合中删除元素时,我通常会做的是将行删除保存在不同的集合中。 像这样,对于你的情况:

          int i = 0; // if you need to dump also the number of the row
          List<DataRow> toDelete = new List<DataRow>();
          foreach (var row in dt.Rows)
          {
              string duration = row[1].ToString();
              if (duration == "")
              {
                  toDelete.Add(row);
              }
              Console.WriteLine(i.ToString() + row[1].ToString());
              i++;
          }
          foreach (var rowToDelete in toDelete)
              row.Delete();
          

          【讨论】:

            【解决方案6】:

            DataTable dt = ConvertToDataTable("C:/ProgramData/3CX/Instance1/Data/Logs/CDRLogs", 4);

                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    string duration = dt.Rows[i][1].ToString();
                    if (duration == "")
                    {
                        dt.Rows[i].Delete();
                        continue;                //Not printing deleted objects. So line after IF block won'nt exist.
                    }
                    Console.WriteLine(i.ToString() + dt.Rows[i][1].ToString());
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-07-01
              • 2013-10-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多