2015-02-13 19 views
9

Sto lavorando con DataTable e ho bisogno di convertirli in un formato di file CSV. La maggior parte delle tabelle con cui lavoro ha oltre 50.000 record, quindi sto cercando di ridurre al minimo il tempo necessario per convertirli.Il modo più efficiente di convertire un DataTable in CSV

Ecco il mio attuale metodo:

public static string table_to_csv(DataTable table) 
    { 
     string file = ""; 

     foreach (DataColumn col in table.Columns) 
      file = string.Concat(file, col.ColumnName, ","); 

     file = file.Remove(file.LastIndexOf(','), 1); 
     file = string.Concat(file, "\r\n"); 

     foreach (DataRow row in table.Rows) 
     { 
      foreach (object item in row.ItemArray) 
       file = string.Concat(file, item.ToString(), ","); 

      file = file.Remove(file.LastIndexOf(','), 1); 
      file = string.Concat(file, "\r\n"); 
     } 

     return file; 
    } 

C'è un modo per migliorare l'efficienza di questo metodo? Sono il benvenuto a tutte le modifiche e idee che hai!

+2

Dal momento che il codice sta funzionando e non si sta affrontando i problemi con esso, forse [Code Review] (http://codereview.stackexchange.com/) è posto migliore per la vostra domanda di StackOverflow. –

+0

Perché stai caricando così tante righe in primo luogo? Sarebbe più semplice utilizzare gli strumenti del database (come SSIS in SQL Server) per esportare i dati in CSV. Oppure utilizzare un DataReader per leggere i dati in modalità Firehose e scriverli in un file. La creazione dell'intera stringa in memoria è * non * efficiente - usa Write e WriteLine per scriverli su un file. Inoltre, è possibile sostituire le concatenazioni ripetute con String.Join, anche se l'utilizzo di 'Write' lo rende un po 'ridondante, come pure –

+0

possibile duplicato di [Converti DataTable in flusso CSV] (http://stackoverflow.com/questions/888181/convert- datatable-to-csv-stream) –

risposta

12

sì, utilizzare un System.Text.StringBuilder per stringhe enormi. Ho implementato questo:

public static string DataTableToCSV(this DataTable datatable, char seperator) 
{ 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < datatable.Columns.Count; i++) 
    { 
     sb.Append(datatable.Columns[i]); 
     if (i < datatable.Columns.Count - 1) 
      sb.Append(seperator); 
    } 
    sb.AppendLine(); 
    foreach (DataRow dr in datatable.Rows) 
    { 
     for (int i = 0; i < datatable.Columns.Count; i++) 
     { 
      sb.Append(dr[i].ToString()); 

      if (i < datatable.Columns.Count - 1) 
       sb.Append(seperator); 
     } 
     sb.AppendLine(); 
    } 
    return sb.ToString(); 
} 
+0

Questa risposta soddisfa i miei requisiti, un DataTable contenente oltre 30k di record utilizzati per richiedere minuti, ora richiede meno di 1 secondo. Grazie. –

+1

come convertire il set di dati in csv? –

+0

@AkhilJain se si dispone di più tabelle all'interno del DataSet - non è possibile. Se si ha una tabella, allora 'string result = DataTableToCSV (myDataSet.Tables [0], ',');' – fubo

2

Ho usato questo metodo che copia dell'oggetto matrice a una gamma cella di Excel anziché copiare riga per riga e poi colonna per colonna & è risultato essere molto efficiente modo

public void ExportToExcel(DataTable dataTable, String pathToSave) 
    { 
     // Create the Excel Application object 
     var excelApp = new ApplicationClass(); 

     // Create a new Excel Workbook 
     Workbook excelWorkbook = excelApp.Workbooks.Add(Type.Missing); 

     int sheetIndex = 0; 

     // Copy the DataTable to an object array 
     var rawData = new object[dataTable.Rows.Count + 1, dataTable.Columns.Count]; 

     // Copy the column names to the first row of the object array 
     for (var col = 0; col < dataTable.Columns.Count; col++) 
     { 
      rawData[0, col] = dataTable.Columns[col].ColumnName; 
     } 

     // Copy the values to the object array 
     for (var col = 0; col < dataTable.Columns.Count; col++) 
     { 
      for (int row = 0; row < dataTable.Rows.Count; row++) 
      { 
       rawData[row + 1, col] = dataTable.Rows[row].ItemArray[col]; 
      } 
     } 

     // Calculate the final column letter 
     string finalColLetter = string.Empty; 
     const string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
     int colCharsetLen = colCharset.Length; 

     if (dataTable.Columns.Count > colCharsetLen) 
     { 
      finalColLetter = colCharset.Substring(
       (dataTable.Columns.Count - 1)/colCharsetLen - 1, 1); 
     } 

     finalColLetter += colCharset.Substring((dataTable.Columns.Count - 1) % colCharsetLen, 1); 

     // Create a new Sheet 
     var excelSheet = (Worksheet)excelWorkbook.Sheets.Add(excelWorkbook.Sheets.Item[++sheetIndex], Type.Missing, 1, XlSheetType.xlWorksheet); 
     excelSheet.Name = dataTable.TableName; 

     // Fast data export to Excel 
     var excelRange = string.Format("A1:{0}{1}", finalColLetter, dataTable.Rows.Count + 1); 
     excelSheet.Range[excelRange, Type.Missing].Value2 = rawData; 

     // Mark the first row as BOLD and BLUE 
     var headerColumnRange = (Range)excelSheet.Rows[1, Type.Missing]; 
     headerColumnRange.Font.Bold = true; 
     headerColumnRange.Font.Color = 0xFF0000; 
     headerColumnRange.EntireColumn.AutoFit(); 

     // Save and Close the Workbook 
     excelWorkbook.SaveAs(pathToSave, XlFileFormat.xlWorkbookNormal, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlExclusive, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); 
     excelWorkbook.Close(true, Type.Missing, Type.Missing); 
     excelWorkbook = null; 

     // Release the Application object 
     excelApp.Quit(); 
     excelApp = null; 

     // Collect the unreferenced objects 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
    } 
5

Ecco un metodo che ho nella mia classe Utility. Funziona bene per quello che sto facendo.

public static void GenerateCSV(DataTable dt) 
    { 
     StringBuilder sb = new StringBuilder(); 
     try 
     { 
      int count = 1; 
      int totalColumns = dt.Columns.Count; 
      foreach (DataColumn dr in dt.Columns) 
      { 
       sb.Append(dr.ColumnName); 

       if (count != totalColumns) 
       { 
        sb.Append(","); 
       } 

       count++; 
      } 

      sb.AppendLine(); 

      string value = String.Empty; 
      foreach (DataRow dr in dt.Rows) 
      { 
       for (int x = 0; x < totalColumns; x++) 
       { 
        value = dr[x].ToString(); 

        if (value.Contains(",") || value.Contains("\"")) 
        { 
         value = '"' + value.Replace("\"", "\"\"") + '"'; 
        } 

        sb.Append(value); 

        if (x != (totalColumns - 1)) 
        { 
         sb.Append(","); 
        } 
       } 

       sb.AppendLine(); 
      } 
     } 
     catch (Exception ex) 
     { 
      // Do something 
     } 
    } 
+1

Risolto come votato in quanto questa soluzione controlla anche le stringhe quando necessario. – Roberto

Problemi correlati