2017-01-02 70 views
0

我试图读取块中的CSV文件,以避免导入大型CSV文件时出现内存不足异常问题。如何在C#中调用IEnumerable集合的Datatable C#

我正在使用IEnumerable集合方法从块中的csv读取数据并将其返回给另一个函数。

但是我得到了System.Collection.Generic.IEnumerable到System.Data.Datatable。隐式转换不可能。

下面是代码:

public void ImportData(string targetPathwithName, System.Data.DataTable dt1, string targetName) 
    { 
     var con = ConfigurationManager.ConnectionStrings["con1"].ConnectionString.ToString(); 
     var connection = new SqlConnection(con); 



     dt1 = GetFileData(targetPathwithName, dt1); 

     connection.Open(); 

     var bulkCopy = new SqlBulkCopy(connection); 
     bulkCopy.DestinationTableName = "[" + targetName + "]"; 
     bulkCopy.WriteToServer(dt1); 
     bulkCopy.Close(); 
     connection.Close(); 

    } 

public static IEnumerable<System.Data.DataTable> GetFileData(string sourceFileFullName, System.Data.DataTable dt1) 
    {    
     var con = ConfigurationManager.ConnectionStrings["con1"].ConnectionString.ToString(); 
     var connection = new SqlConnection(con); 

     int chunkRowCount = 0; 
     int RowCount = 0; 

     using (var sr = new StreamReader(sourceFileFullName)) 
     { 
      if (RowCount != 0) 
      { 
       string Row = null; 
       //Read and display lines from the file until the end of the file is reached.     
       while ((Row = sr.ReadLine()) != null) 
       { 
        chunkRowCount++; 
        //var chunkDataTable = ; //Code for filling datatable or whatever 
        dt1.Rows.Add(); 

        if (chunkRowCount == 10000) 
        { 
         chunkRowCount = 0; 
         yield return dt1; 
         dt1 = null; 
        } 

        else 
        { 
         int i = 0; 

         foreach (string Cell in Row.Split(',')) 
         { 
          if (String.IsNullOrEmpty(Cell)) 
          { 
           dt1.Rows[dt1.Rows.Count - 1][i] = DBNull.Value; 
           i = i + 1; 
          } 
          else if (Cell == "00.00.0000") 
          { 
           dt1.Rows[dt1.Rows.Count - 1][i] = DBNull.Value; 
           i = i + 1; 
          } 
          else 
          { 
           dt1.Rows[dt1.Rows.Count - 1][i] = Cell; 
           i = i + 1; 
          } 
         } 
        } 

       } 
      } 
      RowCount = RowCount + 1; 
     } 
      //return last set of data which less then chunk size 
      if (null != dt1)       
       yield return dt1;    
     } 

如何在另一个函数调用类型System.Data.Datatable的IEnumerable集合?

+0

你确定的函数的返回类型应该是' IEnumerable ' –

+0

@不幸运是的,数据类型应该是IEnumerable 否则我将无法迭代。 – rahul16590

+1

我想你要处理一个'DataTable',所以你想通过它的DataRow集合迭代。那么在这里'IEnumerable '有什么意义? –

回答

1

你必须使用一个foreach循环与一些修改代码如下:

public static void ImportData(string targetPathwithName, System.Data.DataTable dt1, string targetName) 
{ 
    var con = ConfigurationManager.ConnectionStrings["con1"].ConnectionString.ToString(); 
    var connection = new SqlConnection(con); 

    connection.Open(); 
    var bulkCopy = new SqlBulkCopy(connection); 
    foreach (System.Data.DataTable dt in GetFileData(targetPathwithName, dt1)) 
    { 
     bulkCopy.DestinationTableName = "[" + targetName + "]"; 
     bulkCopy.WriteToServer(dt); 
    } 
    bulkCopy.Close(); 
    connection.Close(); 
} 

public static IEnumerable<System.Data.DataTable> GetFileData(string sourceFileFullName, System.Data.DataTable dt1) 
{ 
    var con = ConfigurationManager.ConnectionStrings["con1"].ConnectionString.ToString(); 
    var connection = new SqlConnection(con); 

    int chunkRowCount = 0; 
    //int RowCount = 0; 
    string Row; 

    using (var sr = new StreamReader(sourceFileFullName)) 
    { 
     //if (RowCount != 0) { //this is not meaningful here 

     //Read and display lines from the file until the end of the file is reached.     
     while ((Row = sr.ReadLine()) != null) 
     { 
      chunkRowCount++; 
      //var chunkDataTable = ; //Code for filling datatable or whatever 
      dt1.Rows.Add(); 

      int i = 0; 

      foreach (string Cell in Row.Split(',')) 
      { 
       if (String.IsNullOrEmpty(Cell)) 
       { 
        dt1.Rows[dt1.Rows.Count - 1][i] = DBNull.Value; 
        i = i + 1; 
       } 
       else if (Cell == "00.00.0000") 
       { 
        dt1.Rows[dt1.Rows.Count - 1][i] = DBNull.Value; 
        i = i + 1; 
       } 
       else 
       { 
        dt1.Rows[dt1.Rows.Count - 1][i] = Cell; 
        i = i + 1; 
       } 
      } 

      if (chunkRowCount == 10000) 
      { 
       chunkRowCount = 0; 
       yield return dt1; 
       dt1.Clear(); // = null; 
      } 

     } //end while 

     //} 
     //RowCount = RowCount + 1; 
    } 

    //return last set of data which less then chunk size 
    if (dt1.Rows.Count > 0) 
     yield return dt1; 
} 

我已经测试了这一点,它工作得很好

+0

非常感谢...它像冠军一样....感谢很多 – rahul16590

+0

@ rahul16590所以,我认为这应该是**接受的答案**; D)'Nikunj'提供的其他答案不使用'收益率回报...'方法你正在寻找复制大量数据。此外,该方法消耗大量的RAM内存,因为您需要将所有数据保存在IEnumerableCollection中并将其全部返回到主函数! –

+0

@ S.Serp..correct ...现在我可以导入约。在50秒内100万行... – rahul16590

1

其实你只返回一个数据表而不是IEnumerable。你可以做的是 1)在函数GetFileData中创建IEnumerable的单个实例,如IEnumerable DTables = new IEnumerable(); 2)每次为每个数据块创建一个数据表的新实例,并将该数据表添加到上面定义的IEnumerableCollection中,然后返回该集合。 3)使用函数ImportData中的每个循环读取集合中的所有数据表。