Wie zu beschleunigen dumping eine DataTable in ein Excel-Arbeitsblatt?
Habe ich die folgende routine, die dumps einer DataTable ein Excel-Arbeitsblatt.
private void RenderDataTableOnXlSheet(DataTable dt, Excel.Worksheet xlWk,
string [] columnNames, string [] fieldNames)
{
//render the column names (e.g. headers)
for (int i = 0; i < columnNames.Length; i++)
xlWk.Cells[1, i + 1] = columnNames[i];
//render the data
for (int i = 0; i < fieldNames.Length; i++)
{
for (int j = 0; j < dt.Rows.Count; j++)
{
xlWk.Cells[j + 2, i + 1] = dt.Rows[j][fieldNames[i]].ToString();
}
}
}
Aus welchem Grund auch immer, dumping DataTable mit 25 Spalten und 400 Zeilen dauert etwa 10-15 Sekunden auf meinem relativ modernen PC. Noch länger dauert Tester " Maschinen.
Gibt es irgendetwas, was ich tun kann, um die Geschwindigkeit dieser code? Oder ist interop einfach von Natur aus langsame?
LÖSUNG: Basierend auf Anregungen von Helen Toomik, ich habe Sie geändert, die Methode und es sollte jetzt funktionieren für verschiedene gängige Datentypen wie int32, double, datetime, string). Fühlen Sie sich frei, um es zu erweitern. Die Geschwindigkeit für die Verarbeitung meiner dataset ging von 15 Sekunden der unter 1.
private void RenderDataTableOnXlSheet(DataTable dt, Excel.Worksheet xlWk, string [] columnNames, string [] fieldNames)
{
Excel.Range rngExcel = null;
Excel.Range headerRange = null;
try
{
//render the column names (e.g. headers)
for (int i = 0; i < columnNames.Length; i++)
xlWk.Cells[1, i + 1] = columnNames[i];
//for each column, create an array and set the array
//to the excel range for that column.
for (int i = 0; i < fieldNames.Length; i++)
{
string[,] clnDataString = new string[dt.Rows.Count, 1];
int[,] clnDataInt = new int[dt.Rows.Count, 1];
double[,] clnDataDouble = new double[dt.Rows.Count, 1];
string columnLetter = char.ConvertFromUtf32("A".ToCharArray()[0] + i);
rngExcel = xlWk.get_Range(columnLetter + "2", Missing.Value);
rngExcel = rngExcel.get_Resize(dt.Rows.Count, 1);
string dataTypeName = dt.Columns[fieldNames[i]].DataType.Name;
for (int j = 0; j < dt.Rows.Count; j++)
{
if (fieldNames[i].Length > 0)
{
switch (dataTypeName)
{
case "Int32":
clnDataInt[j, 0] = Convert.ToInt32(dt.Rows[j][fieldNames[i]]);
break;
case "Double":
clnDataDouble[j, 0] = Convert.ToDouble(dt.Rows[j][fieldNames[i]]);
break;
case "DateTime":
if (fieldNames[i].ToLower().Contains("time"))
clnDataString[j, 0] = Convert.ToDateTime(dt.Rows[j][fieldNames[i]]).ToShortTimeString();
else if (fieldNames[i].ToLower().Contains("date"))
clnDataString[j, 0] = Convert.ToDateTime(dt.Rows[j][fieldNames[i]]).ToShortDateString();
else
clnDataString[j, 0] = Convert.ToDateTime(dt.Rows[j][fieldNames[i]]).ToString();
break;
default:
clnDataString[j, 0] = dt.Rows[j][fieldNames[i]].ToString();
break;
}
}
else
clnDataString[j, 0] = string.Empty;
}
//set values in the sheet wholesale.
if (dataTypeName == "Int32")
rngExcel.set_Value(Missing.Value, clnDataInt);
else if (dataTypeName == "Double")
rngExcel.set_Value(Missing.Value, clnDataDouble);
else
rngExcel.set_Value(Missing.Value, clnDataString);
}
//figure out the letter of the last column (supports 1 letter column names)
string lastColumn = char.ConvertFromUtf32("A".ToCharArray()[0] + columnNames.Length - 1);
//make the header range bold
headerRange = xlWk.get_Range("A1", lastColumn + "1");
headerRange.Font.Bold = true;
//autofit for better view
xlWk.Columns.AutoFit();
}
finally
{
ReleaseObject(headerRange);
ReleaseObject(rngExcel);
}
}
private void ReleaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch
{
obj = null;
}
finally
{
GC.Collect();
}
}
Danke. Sieht interessant aus.
Das ist sehr gut. Das einzige, was ich empfehlen würde, ist der Typ-Vergleich Sachen außerhalb der for-Schleife für die Zeilen. Es würde bedeuten, man müsste eine Schleife für jeden geben, aber dann müssen Sie nicht haben, um zu vergleichen-Typen für jede Zeile. Aber so oder so, sehr hilfreich.
InformationsquelleAutor AngryHacker | 2010-04-22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Statt die Zelle Werte eins nach dem anderen, tun Sie es in eine batch.
Schritt 1. Übertragen Sie die Daten aus der DataTable in ein array mit den gleichen Dimensionen.
Schritt 2. Definieren Sie ein Excel-Range-Objekt, das über den entsprechenden Bereich.
Schritt 3. Stellen Sie den Bereich ein.Wert in das array.
Dieser wird viel schneller sein, da haben Sie insgesamt zwei Anrufe über die Interop-Grenze (um die "Range" - Objekt, setzen dessen Wert), statt zwei pro Zelle (Zelle bekommen, Wert).
Gibt es einige Beispiel-code bei MSDN KB-Artikel 302096.
InformationsquelleAutor Helen Toomik
Interop ist von Natur aus sehr langsam.
Es gibt einen großen overhead bei jedem Aufruf.
Um ihn zu beschleunigen versuchen das zurückschreiben eines object-Arrays mit Daten auf einen Bereich von Zellen in einer Zuweisungsanweisung verwenden.
Oder ob dies ein ernstes problem, versuchen Sie es mit einer Verwalteten Code Excel-Erweiterungen, die das Lesen/schreiben von Daten mithilfe von verwaltetem code, die über die XXL-Schnittstelle. (Add-in-Express, Verwaltet XLL etc.)
InformationsquelleAutor Charles Williams
Wenn Sie ein recordset, ist der Schnellste Weg, um schreiben zu Excel wird die CopyFromRecordset-Methode.
InformationsquelleAutor Fionnuala
Haben Sie eine bestimmte Anforderung zu gehen, das die COM-Automatisierung route? Wenn nicht, haben Sie ein paar andere Möglichkeiten.
Verwenden Sie den OLE DB-Anbieter zu erstellen/schreiben Sie in eine Excel-Datei
http://support.microsoft.com/kb/316934
Verwenden Sie ein Drittanbieter-Bibliothek zu schreiben, um Excel. Je nach Lizenz-Anforderungen gibt es ein paar Optionen.
Update: Eine gute Kostenlose Bibliothek ist NPOI http://npoi.codeplex.com/
Schreiben der Daten in eine csv-Datei, und laden Sie diese in Excel
Schreiben, die Sie als XML-Daten, die geladen werden können, in Excel.
Verwenden Sie das Open XML SDK
http://www.microsoft.com/downloads/details.aspx?familyid=C6E744E5-36E9-45F5-8D8C-331DF206E0D0&displaylang=en
Verwenden von OLEDB schreiben Sie auf mehrere Blätter. - Blätter.codeproject.com/KB/miscctrl/Excel_data_access.aspx Morgen werde ich aktualisieren, mit sehr guter open-source-Bibliothek, die ich verwende, aber ich weiß einfach nicht an den Namen erinnern jetzt, es bietet die volle Kontrolle, Formatierung etc.
InformationsquelleAutor Chris Taylor
Konnten Sie erstellen ein Excel-add-in mit VBA-code zu tun, alle Ihre db-schweres heben. aus .NET, alles was Sie brauchen zu tun ist, zu instanziieren, Excel, fügen Sie die add-in, und rufen Sie die Excel-VBA-routine, die übergabe beliebiger Parameter, die es braucht, um die Ausführung Ihrer SQL-Anweisungen.
InformationsquelleAutor david f
Ich Stimme mit Charles. Interop ist wirklich langsam. Aber versuchen Sie dies:
HTH
InformationsquelleAutor Raja