Fragensteller
große Menge Tabellen-Daten an Excel zum Editieren übergeben.

Frage
-
Hallo,
der Kunde bekommt große Listen von Daten in Excel geliefert und möchte sie über Excel in eine Liste in ein C#-Programm übergeben.
Auch soll das andersherum gehen: eine große Liste vom BindingList< Typx> wir in einem Gridview angezeigt und soll ggf, an Excel zum weiter bearbeiten übergeben werden und wenn man in Excel fertig ist, sollen die Daten wieder zurück in die BindingList< Typx> und in einem DataGridView angezeigt werden.
Die Übergabe an Excel bekomme ich zwar hin, ggf, auch die Rückgabe, aber das dauert ewig.
Kann man das beschleunigen?
Danke
Montag, 26. November 2018 18:38
Alle Antworten
-
Hi,
es gibt immer Möglichkeiten einer Beschleunigung. Dazu müsste man aber wissen, was Du konkret machst und am besten noch, wo in Deinem Algorithmus die Zeit verbraten wird. Typische Verdächtige sind Select und Activate bei Nutzung des Objektmodells oder eine fehlende schema.ini bei Nutzung der Jet.--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und TricksMontag, 26. November 2018 19:03 -
Hi,
in meinem Programm werden die Daten in Form von BindingList< Typx> gehalten und irgendwohin serialisiert.
Das sin aber Daten, die erstmal in Form von irgendwie formatierten Text von Kunden geliefert werden.
Zum Import wollte ich Excel nutzen, wo der User (nicht der Kunde und Datenlieferant) die Daten aufbereiten kann.
Also von Excel übernehmen.
---------
anderer Fall:
Die Daten sind schon im Programm. Der User will sie ändern.
Dazu sollen die Daten wieder an Excel übergeben werden - in Excel werden sie bearbeitet, Excel geschlossen und mein Programm übernimmt die Daten - so der Wunsch um nicht alles selber programmieren zu müssen.
Allerdings dauert das bei 1000 Zeilen schon sehr lange.
Ich wäre dankbar für eine bessere Idee.
Montag, 26. November 2018 22:06 -
Hi,
man kann Exceldaten über OleDbConnection auch direkt lesen und schreiben. In der Regel ist das erheblich schneller als zu versuchen, sie einzulesen, zu transformieren und auf irgendeinem Weg dann wieder zu schreiben.
Da Du nicht schreibst, wie Du das bisher machst, hier erstmal ein generelles Beispiel:
Read and Write Excel Documents Using OLEDB
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, RemotesupportMontag, 26. November 2018 22:20Moderator -
Hi,
das Schreiben von 1000 Zeilen mit 50 Spalten in eine csv-Datei dauert in meiner Demo nur 27 ms. Hier mal die Demo.Imports System.IO Module Module42 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.WriteLine("weiter mit Taste") Console.ReadKey() End Sub Friend Class Demo Private fileName As String = "c:\temp\x.csv" Friend Sub Execute() Dim sw As New Stopwatch sw.Start() Using wrt As New StreamWriter(fileName) For i = 1 To 1000 For k = 1 To 50 wrt.Write($"Zelle {i} {k}") Next wrt.WriteLine() Next End Using sw.Stop() Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms") End Sub End Class End Module
Dasselbe mit Objektautomatisierung für 1000 Zeilen mit 50 Spalten in 50000 Einzelzellen dauert 140 Sekunden:
Imports Microsoft.Office.Interop Module Module43 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.WriteLine("weiter mit Taste") Console.ReadKey() End Sub Friend Class Demo Private fileName As String = "c:\temp\x.xlsx" Friend Sub Execute() Dim sw As New Stopwatch sw.Start() Dim xlApp As New Excel.Application Dim xlWb As Excel.Workbook = xlApp.Workbooks.Add() Dim xlSh As Excel.Worksheet = CType(xlWb.Worksheets(1), Excel.Worksheet) For i = 1 To 1000 For k = 1 To 50 xlSh.Cells(i, k) = $"Zelle {i} {k}" Next Next xlWb.SaveAs(fileName) xlWb.Close() xlApp = Nothing sw.Stop() Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms") End Sub End Class End Module
Wenn man in den 50000 Zellen mit der Objektautomatisierung nur 50 Zellinhalte ändert, dann dauert das incl. Datei Öffnen und Speichern nur 7 Sekunden.
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks
- Bearbeitet Peter Fleischer Dienstag, 27. November 2018 07:33
Dienstag, 27. November 2018 06:09 -
Hi,
man kann Exceldaten über OleDbConnection auch direkt lesen und schreiben. In der Regel ist das erheblich schneller als zu versuchen, sie einzulesen, zu transformieren und auf irgendeinem Weg dann wieder zu schreiben.
Ok, Vielen Dank, das ist schonmal schweine-schnell ...
Bisher wurde es über Interop.Excel gemacht, die Zellen einzeln gelesen und ausgewertet, aber auch bei einem Fehler wieder in Excel angezeigt wo der Fehler liegt.
Nur dauert das eben ewig bei 1000 und mehr Zeilen
MfG
Dienstag, 27. November 2018 08:17 -
Hi,
hier mal eine kleine Demo, in der 1000 Zeilen mit 50 Spalten in einer Excel-Tabelle mit OleDb erzeugt werden. Das dauert bei mir mit 8 Sekunden:Imports System.Data.OleDb Imports System.IO Imports Microsoft.Office.Interop Module Module44 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.WriteLine("weiter mit Taste") Console.ReadKey() End Sub Friend Class Demo Private fileName As String = "c:\temp\x.xlsx" Private cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0 Xml;HDR=YES"";" Friend Sub Execute() ' Vorbereitung einer leeren Tabelle File.Delete(fileName) Dim xlApp As New Excel.Application Dim xlWb As Excel.Workbook = xlApp.Workbooks.Add Dim xlSh As Excel.Worksheet = CType(xlWb.Worksheets(1), Excel.Worksheet) xlSh.Cells(1, 1) = $"ID" For i = 2 To 50 xlSh.Cells(1, i) = $"Spalte{i:00}" Next xlWb.SaveAs(fileName) xlWb.Close() xlApp = Nothing ' Messung des Zugriffes Dim sw As New Stopwatch sw.Start() Dim dt As New DataTable Using cn As New OleDbConnection(String.Format(cnString, fileName)) Using da As New OleDbDataAdapter("SELECT * FROM [Tabelle1$]", cn) da.Fill(dt) With dt.Columns(0) .AutoIncrement = True .AutoIncrementSeed = 1 .AutoIncrementStep = 1 End With For i = 1 To 1000 Dim r = dt.NewRow For k = 1 To 49 r(k) = $"Zelle {i} {k}" Next dt.Rows.Add(r) Next Dim cb As New OleDbCommandBuilder(da) cb.QuotePrefix = "[" cb.QuoteSuffix = "]" da.Update(dt) End Using End Using sw.Stop() Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms") End Sub End Class End Module
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Bearbeitet Peter Fleischer Dienstag, 27. November 2018 09:38
Dienstag, 27. November 2018 08:22 -
Hallo zusammen,
direkt mit INSERT, UPDATE Statements geht das erheblich schneller über OleDb:
class Program { static void Main(string[] args) { WriteExcel(); Console.WriteLine( "" ); WriteExcel2(); Console.WriteLine( "" ); WriteExcel(); Console.WriteLine( "" ); WriteExcel2(); Console.ReadKey(); } static void WriteExcel() { Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"; String sqlStatement = String.Empty; using( OleDbConnection conn = new OleDbConnection( connString ) ) { conn.Open(); using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) { for( int i = 1; i <= 1000; i++ ) { String iAsString = i.ToString(); sqlStatement = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value] ) VALUES ( {iAsString}, 'Name {iAsString}', 'Wert {iAsString}' )"; cmd.CommandText = sqlStatement; cmd.ExecuteNonQuery(); } } conn.Close(); } Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); } static void WriteExcel2() { Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"; String sqlStatement = String.Empty; using( OleDbConnection conn = new OleDbConnection( connString ) ) { conn.Open(); using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) { cmd.CommandText = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value] ) VALUES ( ?, ?, ? )"; cmd.Parameters.AddWithValue( "@ID", 0 ); cmd.Parameters.AddWithValue( "@Name", "" ); cmd.Parameters.AddWithValue( "@Value", "" ); for( int i = 1; i <= 1000; i++ ) { String iAsString = i.ToString(); cmd.Parameters["@ID"].Value = iAsString; cmd.Parameters["@Name"].Value = "Name " + iAsString; cmd.Parameters["@Value"].Value = "Wert " + iAsString; cmd.ExecuteNonQuery(); } } conn.Close(); } Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); } }
Der allererste Lauf braucht etwas länger, ich nehme an, weil die Exceldatei erst geöffnet werden muss. Die Zeiten bei mir sind in der Regel in etwa wie folgt:
Start: 27.11.2018 09:43:01.2051 Ende : 27.11.2018 09:43:02.6479 Start: 27.11.2018 09:43:02.6489 Ende : 27.11.2018 09:43:03.0822 Start: 27.11.2018 09:43:03.0832 Ende : 27.11.2018 09:43:03.4620 Start: 27.11.2018 09:43:03.4620 Ende : 27.11.2018 09:43:03.8911
Ab dem zweiten Durchlauf ca. 400 ms für jeweils 1000 Datensätze mit 3 Spalten. Aber auch mit 50 Spalten sollte es nur unwesentlich langsamer sein.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport- Bearbeitet Stefan FalzModerator Dienstag, 27. November 2018 11:37
Dienstag, 27. November 2018 08:48Moderator -
Hi Stefan,
mit nur 3 Spalten geht das natürlich viel schneller als mein Beispiel mit 50 Spalten. Außerdem ist bei der Arbeit ohne Datenpuffer für das GridView nur die Nutzung von INSERT und UPDATE mit mehr Aufwand verbunden als die Nutzung z.B. einer DataTable wie in meinem Beispiel. Letztendlich muss aber der Anwendungsprogrammierer auf Basis der Aufgabenstellung entscheiden, welche Technologie am besten passt.Meine Messungen ergeben, dass es mit separaten INSERT's 1 Sekunde länger (8 Sekunden) dauert als mit dem CommandBuilder und einer DataTable bei gleicher Datenmenge (1000 Sätze mit 50 Spalten).
Imports System.Data.OleDb Imports System.IO Imports Microsoft.Office.Interop Module Module45 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.WriteLine("weiter mit Taste") Console.ReadKey() End Sub Friend Class Demo Private fileName As String = "c:\temp\x.xlsx" Private cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0 Xml;HDR=YES"";" Friend Sub Execute() ' Vorbereitung einer leeren Tabelle File.Delete(fileName) Dim xlApp As New Excel.Application Dim xlWb As Excel.Workbook = xlApp.Workbooks.Add Dim xlSh As Excel.Worksheet = CType(xlWb.Worksheets(1), Excel.Worksheet) For i = 1 To 50 xlSh.Cells(1, i) = $"Spalte{i:00}" Next xlWb.SaveAs(fileName) xlWb.Close() xlApp = Nothing ' Messung des Zugriffes Dim sw As New Stopwatch sw.Start() Using cn As New OleDbConnection(String.Format(cnString, fileName)) Using cmd As New OleDbCommand("", cn) Dim cmdText As String = "INSERT INTO [Tabelle1$] ({0}) VALUES ({1})" Dim cmdText1(49) As String Dim cmdText2(49) As String For i = 0 To 49 cmdText1(i) = $"Spalte{i + 1:00}" cmdText2(i) = "?" cmd.Parameters.Add($"Par{i + 1:00}", OleDbType.VarWChar) Next cmd.CommandText = String.Format(cmdText, String.Join(",", cmdText1), String.Join(",", cmdText2)) cn.Open() For i = 1 To 1000 For k = 0 To 49 cmd.Parameters(k).Value = $"Zelle {i} {k}" Next cmd.ExecuteNonQuery() Next End Using End Using sw.Stop() Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms") End Sub End Class End Module
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und TricksDienstag, 27. November 2018 10:03 -
Hallo Peter,
unsere Codebeispiele sind natürlich nicht direkt vergleichbar. Folgendes ist im Release mit ca. 1,5 bis 3 Sekunden durch. Im Debugmodus dauert es ungefähr 4 bis 7 Sekunden.
Die Variante mit den OleDbParametern dauert bei mir zwischen 2,5 und 4 Sekunden im Release und zwischen 4 und 8 Sekunden im Debug, wobei es natürlich auch auf die bisherigen Inhalte der Exceldatei ankommt. Wenn dort schon zigtausende Datensätze drinstehen, dauert es etwas länger, die Datei zu schreiben.
Aber wie Du schon geschrieben hast: Es ist nun am TE, zu entscheiden, was für ihn das Beste wäre und ob eine der genannten Optionen für ihn in Frage kommt.
class Program { static void Main(string[] args) { WriteExcel(); Console.WriteLine( "Press the any key to continue: " ); Console.ReadKey(); } static void WriteExcel() { Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"; String sqlStatement = String.Empty; using( OleDbConnection conn = new OleDbConnection( connString ) ) { conn.Open(); using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) { for( int i = 1; i <= 1000; i++ ) { String iAsString = i.ToString(); sqlStatement = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value], [Spalte4], [Spalte5], [Spalte6], [Spalte7], [Spalte8], [Spalte9], [Spalte10], [Spalte11], [Spalte12], [Spalte13], [Spalte14], [Spalte15], [Spalte16], [Spalte17], [Spalte18], [Spalte19], [Spalte20], [Spalte21], [Spalte22], [Spalte23], [Spalte24], [Spalte25], [Spalte26], [Spalte27], [Spalte28], [Spalte29], [Spalte30], [Spalte31], [Spalte32], [Spalte33], [Spalte34], [Spalte35], [Spalte36], [Spalte37], [Spalte38], [Spalte39], [Spalte40], [Spalte41], [Spalte42], [Spalte43], [Spalte44], [Spalte45], [Spalte46], [Spalte47], [Spalte48], [Spalte49], [Spalte50] ) VALUES ( {iAsString}, 'Name {iAsString}', 'Wert {iAsString}', 'Spalte4 {iAsString}', 'Spalte5 {iAsString}', 'Spalte6 {iAsString}', 'Spalte7 {iAsString}', 'Spalte8 {iAsString}', 'Spalte9 {iAsString}', 'Spalte10 {iAsString}', 'Spalte11 {iAsString}', 'Spalte12 {iAsString}', 'Spalte13 {iAsString}', 'Spalte14 {iAsString}', 'Spalte15 {iAsString}', 'Spalte16 {iAsString}', 'Spalte17 {iAsString}', 'Spalte18 {iAsString}', 'Spalte19 {iAsString}', 'Spalte20 {iAsString}', 'Spalte21 {iAsString}', 'Spalte22 {iAsString}', 'Spalte23 {iAsString}', 'Spalte24 {iAsString}', 'Spalte25 {iAsString}', 'Spalte26 {iAsString}', 'Spalte27 {iAsString}', 'Spalte28 {iAsString}', 'Spalte29 {iAsString}', 'Spalte30 {iAsString}', 'Spalte31 {iAsString}', 'Spalte32 {iAsString}', 'Spalte33 {iAsString}', 'Spalte34 {iAsString}', 'Spalte35 {iAsString}', 'Spalte36 {iAsString}', 'Spalte37 {iAsString}', 'Spalte38 {iAsString}', 'Spalte39 {iAsString}', 'Spalte40 {iAsString}', 'Spalte41 {iAsString}', 'Spalte42 {iAsString}', 'Spalte43 {iAsString}', 'Spalte44 {iAsString}', 'Spalte45 {iAsString}', 'Spalte46 {iAsString}', 'Spalte47 {iAsString}', 'Spalte48 {iAsString}', 'Spalte49 {iAsString}', 'Spalte50 {iAsString}' )"; cmd.CommandText = sqlStatement; cmd.ExecuteNonQuery(); } } conn.Close(); } Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); } static void WriteExcel2() { Console.WriteLine( $"Start: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); String connString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=X:\Ordner\Test.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"; String sqlStatement = String.Empty; using( OleDbConnection conn = new OleDbConnection( connString ) ) { conn.Open(); using( OleDbCommand cmd = new OleDbCommand( String.Empty, conn ) ) { cmd.CommandText = $@"INSERT INTO [Tabelle1$] ( [ID], [Name], [Value], [Spalte4], [Spalte5], [Spalte6], [Spalte7], [Spalte8], [Spalte9], [Spalte10], [Spalte11], [Spalte12], [Spalte13], [Spalte14], [Spalte15], [Spalte16], [Spalte17], [Spalte18], [Spalte19], [Spalte20], [Spalte21], [Spalte22], [Spalte23], [Spalte24], [Spalte25], [Spalte26], [Spalte27], [Spalte28], [Spalte29], [Spalte30], [Spalte31], [Spalte32], [Spalte33], [Spalte34], [Spalte35], [Spalte36], [Spalte37], [Spalte38], [Spalte39], [Spalte40], [Spalte41], [Spalte42], [Spalte43], [Spalte44], [Spalte45], [Spalte46], [Spalte47], [Spalte48], [Spalte49], [Spalte50] ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"; cmd.Parameters.AddWithValue( "@ID", 0 ); cmd.Parameters.AddWithValue( "@Name", "" ); cmd.Parameters.AddWithValue( "@Value", "" ); cmd.Parameters.AddWithValue( "@Spalte4", "" ); cmd.Parameters.AddWithValue( "@Spalte5", "" ); cmd.Parameters.AddWithValue( "@Spalte6", "" ); cmd.Parameters.AddWithValue( "@Spalte7", "" ); cmd.Parameters.AddWithValue( "@Spalte8", "" ); cmd.Parameters.AddWithValue( "@Spalte9", "" ); cmd.Parameters.AddWithValue( "@Spalte10", "" ); cmd.Parameters.AddWithValue( "@Spalte11", "" ); cmd.Parameters.AddWithValue( "@Spalte12", "" ); cmd.Parameters.AddWithValue( "@Spalte13", "" ); cmd.Parameters.AddWithValue( "@Spalte14", "" ); cmd.Parameters.AddWithValue( "@Spalte15", "" ); cmd.Parameters.AddWithValue( "@Spalte16", "" ); cmd.Parameters.AddWithValue( "@Spalte17", "" ); cmd.Parameters.AddWithValue( "@Spalte18", "" ); cmd.Parameters.AddWithValue( "@Spalte19", "" ); cmd.Parameters.AddWithValue( "@Spalte20", "" ); cmd.Parameters.AddWithValue( "@Spalte21", "" ); cmd.Parameters.AddWithValue( "@Spalte22", "" ); cmd.Parameters.AddWithValue( "@Spalte23", "" ); cmd.Parameters.AddWithValue( "@Spalte24", "" ); cmd.Parameters.AddWithValue( "@Spalte25", "" ); cmd.Parameters.AddWithValue( "@Spalte26", "" ); cmd.Parameters.AddWithValue( "@Spalte27", "" ); cmd.Parameters.AddWithValue( "@Spalte28", "" ); cmd.Parameters.AddWithValue( "@Spalte29", "" ); cmd.Parameters.AddWithValue( "@Spalte30", "" ); cmd.Parameters.AddWithValue( "@Spalte31", "" ); cmd.Parameters.AddWithValue( "@Spalte32", "" ); cmd.Parameters.AddWithValue( "@Spalte33", "" ); cmd.Parameters.AddWithValue( "@Spalte34", "" ); cmd.Parameters.AddWithValue( "@Spalte35", "" ); cmd.Parameters.AddWithValue( "@Spalte36", "" ); cmd.Parameters.AddWithValue( "@Spalte37", "" ); cmd.Parameters.AddWithValue( "@Spalte38", "" ); cmd.Parameters.AddWithValue( "@Spalte39", "" ); cmd.Parameters.AddWithValue( "@Spalte40", "" ); cmd.Parameters.AddWithValue( "@Spalte41", "" ); cmd.Parameters.AddWithValue( "@Spalte42", "" ); cmd.Parameters.AddWithValue( "@Spalte43", "" ); cmd.Parameters.AddWithValue( "@Spalte44", "" ); cmd.Parameters.AddWithValue( "@Spalte45", "" ); cmd.Parameters.AddWithValue( "@Spalte46", "" ); cmd.Parameters.AddWithValue( "@Spalte47", "" ); cmd.Parameters.AddWithValue( "@Spalte48", "" ); cmd.Parameters.AddWithValue( "@Spalte49", "" ); cmd.Parameters.AddWithValue( "@Spalte50", "" ); for( int i = 1; i <= 1000; i++ ) { String iAsString = i.ToString(); cmd.Parameters["@ID"].Value = iAsString; cmd.Parameters["@Name"].Value = "Name " + iAsString; cmd.Parameters["@Value"].Value = "Wert " + iAsString; cmd.Parameters["@Spalte4"].Value = "Spalte 4 " + iAsString; cmd.Parameters["@Spalte5"].Value = "Spalte 5 " + iAsString; cmd.Parameters["@Spalte6"].Value = "Spalte 6 " + iAsString; cmd.Parameters["@Spalte7"].Value = "Spalte 7 " + iAsString; cmd.Parameters["@Spalte8"].Value = "Spalte 8 " + iAsString; cmd.Parameters["@Spalte9"].Value = "Spalte 9 " + iAsString; cmd.Parameters["@Spalte10"].Value = "Spalte 10 " + iAsString; cmd.Parameters["@Spalte11"].Value = "Spalte 11 " + iAsString; cmd.Parameters["@Spalte12"].Value = "Spalte 12 " + iAsString; cmd.Parameters["@Spalte13"].Value = "Spalte 13 " + iAsString; cmd.Parameters["@Spalte14"].Value = "Spalte 14 " + iAsString; cmd.Parameters["@Spalte15"].Value = "Spalte 15 " + iAsString; cmd.Parameters["@Spalte16"].Value = "Spalte 16 " + iAsString; cmd.Parameters["@Spalte17"].Value = "Spalte 17 " + iAsString; cmd.Parameters["@Spalte18"].Value = "Spalte 18 " + iAsString; cmd.Parameters["@Spalte19"].Value = "Spalte 29 " + iAsString; cmd.Parameters["@Spalte20"].Value = "Spalte 20 " + iAsString; cmd.Parameters["@Spalte21"].Value = "Spalte 21 " + iAsString; cmd.Parameters["@Spalte22"].Value = "Spalte 22 " + iAsString; cmd.Parameters["@Spalte23"].Value = "Spalte 23 " + iAsString; cmd.Parameters["@Spalte24"].Value = "Spalte 24 " + iAsString; cmd.Parameters["@Spalte25"].Value = "Spalte 25 " + iAsString; cmd.Parameters["@Spalte26"].Value = "Spalte 26 " + iAsString; cmd.Parameters["@Spalte27"].Value = "Spalte 27 " + iAsString; cmd.Parameters["@Spalte28"].Value = "Spalte 28 " + iAsString; cmd.Parameters["@Spalte29"].Value = "Spalte 39 " + iAsString; cmd.Parameters["@Spalte30"].Value = "Spalte 30 " + iAsString; cmd.Parameters["@Spalte31"].Value = "Spalte 31 " + iAsString; cmd.Parameters["@Spalte32"].Value = "Spalte 32 " + iAsString; cmd.Parameters["@Spalte33"].Value = "Spalte 33 " + iAsString; cmd.Parameters["@Spalte34"].Value = "Spalte 34 " + iAsString; cmd.Parameters["@Spalte35"].Value = "Spalte 35 " + iAsString; cmd.Parameters["@Spalte36"].Value = "Spalte 36 " + iAsString; cmd.Parameters["@Spalte37"].Value = "Spalte 37 " + iAsString; cmd.Parameters["@Spalte38"].Value = "Spalte 38 " + iAsString; cmd.Parameters["@Spalte39"].Value = "Spalte 49 " + iAsString; cmd.Parameters["@Spalte40"].Value = "Spalte 40 " + iAsString; cmd.Parameters["@Spalte41"].Value = "Spalte 41 " + iAsString; cmd.Parameters["@Spalte42"].Value = "Spalte 42 " + iAsString; cmd.Parameters["@Spalte43"].Value = "Spalte 43 " + iAsString; cmd.Parameters["@Spalte44"].Value = "Spalte 44 " + iAsString; cmd.Parameters["@Spalte45"].Value = "Spalte 45 " + iAsString; cmd.Parameters["@Spalte46"].Value = "Spalte 46 " + iAsString; cmd.Parameters["@Spalte47"].Value = "Spalte 47 " + iAsString; cmd.Parameters["@Spalte48"].Value = "Spalte 48 " + iAsString; cmd.Parameters["@Spalte49"].Value = "Spalte 49 " + iAsString; cmd.Parameters["@Spalte50"].Value = "Spalte 50 " + iAsString; cmd.ExecuteNonQuery(); } } conn.Close(); } Console.WriteLine( $"Ende: {DateTime.Now.ToString( "dd.MM.yyyy HH:mm:ss.ffff" )}" ); } }
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport- Bearbeitet Stefan FalzModerator Dienstag, 27. November 2018 11:59
Dienstag, 27. November 2018 11:59Moderator -
Hi,
ich bin ja OpenXML- Fan. Vor allem was Geschwindigkeit betrifft, ist das eine Überlegung wert.
Hier mal eine kleine Deme (1000x50):
using System; namespace OpenXMLSample { class Program { static void Main(string[] args) { Report report = new Report(); report.CreateExcelDoc(@"C:\Temp\Report1.xlsx"); Console.WriteLine("Excel file has created!"); Console.ReadLine(); } } }
using System; using System.Collections.Generic; namespace OpenXMLSample { public class Employee { public int Id { get; set; } public string Name { get; set; } public DateTime DOB { get; set; } public decimal Salary { get; set; } public string Spalte05 { get; set; } public string Spalte06 { get; set; } public string Spalte07 { get; set; } public string Spalte08 { get; set; } public string Spalte09 { get; set; } public string Spalte10 { get; set; } public string Spalte11 { get; set; } public string Spalte12 { get; set; } public string Spalte13 { get; set; } public string Spalte14 { get; set; } public string Spalte15 { get; set; } public string Spalte16 { get; set; } public string Spalte17 { get; set; } public string Spalte18 { get; set; } public string Spalte19 { get; set; } public string Spalte20 { get; set; } public string Spalte21 { get; set; } public string Spalte22 { get; set; } public string Spalte23 { get; set; } public string Spalte24 { get; set; } public string Spalte25 { get; set; } public string Spalte26 { get; set; } public string Spalte27 { get; set; } public string Spalte28 { get; set; } public string Spalte29 { get; set; } public string Spalte30 { get; set; } public string Spalte31 { get; set; } public string Spalte32 { get; set; } public string Spalte33 { get; set; } public string Spalte34 { get; set; } public string Spalte35 { get; set; } public string Spalte36 { get; set; } public string Spalte37 { get; set; } public string Spalte38 { get; set; } public string Spalte39 { get; set; } public string Spalte40 { get; set; } public string Spalte41 { get; set; } public string Spalte42 { get; set; } public string Spalte43 { get; set; } public string Spalte44 { get; set; } public string Spalte45 { get; set; } public string Spalte46 { get; set; } public string Spalte47 { get; set; } public string Spalte48 { get; set; } public string Spalte49 { get; set; } public string Spalte50 { get; set; } } public sealed class Employees { static List<Employee> _employees; const int COUNT = 1000; public static List<Employee> EmployeesList { private set { } get { return _employees; } } static Employees() { Initialize(); } private static void Initialize() { _employees = new List<Employee>(); Random random = new Random(); for (int i = 0; i < COUNT; i++) { _employees.Add(new Employee() { Id = i, Name = "Employee " + i, DOB = new DateTime(1999, 1, 1).AddMonths(i), Salary = random.Next(100, 10000), Spalte05= random.Next(100, 10000).ToString(), Spalte06= random.Next(100, 10000).ToString(), Spalte07= random.Next(100, 10000).ToString(), Spalte08= random.Next(100, 10000).ToString(), Spalte09= random.Next(100, 10000).ToString(), Spalte10= random.Next(100, 10000).ToString(), Spalte11= random.Next(100, 10000).ToString(), Spalte12= random.Next(100, 10000).ToString(), Spalte13= random.Next(100, 10000).ToString(), Spalte14= random.Next(100, 10000).ToString(), Spalte15= random.Next(100, 10000).ToString(), Spalte16= random.Next(100, 10000).ToString(), Spalte17= random.Next(100, 10000).ToString(), Spalte18= random.Next(100, 10000).ToString(), Spalte19= random.Next(100, 10000).ToString(), Spalte20 = random.Next(100, 10000).ToString(), Spalte21 = random.Next(100, 10000).ToString(), Spalte22 = random.Next(100, 10000).ToString(), Spalte23 = random.Next(100, 10000).ToString(), Spalte24 = random.Next(100, 10000).ToString(), Spalte25 = random.Next(100, 10000).ToString(), Spalte26 = random.Next(100, 10000).ToString(), Spalte27 = random.Next(100, 10000).ToString(), Spalte28 = random.Next(100, 10000).ToString(), Spalte29 = random.Next(100, 10000).ToString(), Spalte30 = random.Next(100, 10000).ToString(), Spalte31 = random.Next(100, 10000).ToString(), Spalte32 = random.Next(100, 10000).ToString(), Spalte33 = random.Next(100, 10000).ToString(), Spalte34 = random.Next(100, 10000).ToString(), Spalte35 = random.Next(100, 10000).ToString(), Spalte36 = random.Next(100, 10000).ToString(), Spalte37 = random.Next(100, 10000).ToString(), Spalte38 = random.Next(100, 10000).ToString(), Spalte39 = random.Next(100, 10000).ToString(), Spalte40 = random.Next(100, 10000).ToString(), Spalte41 = random.Next(100, 10000).ToString(), Spalte42 = random.Next(100, 10000).ToString(), Spalte43 = random.Next(100, 10000).ToString(), Spalte44 = random.Next(100, 10000).ToString(), Spalte45 = random.Next(100, 10000).ToString(), Spalte46 = random.Next(100, 10000).ToString(), Spalte47 = random.Next(100, 10000).ToString(), Spalte48 = random.Next(100, 10000).ToString(), Spalte49 = random.Next(100, 10000).ToString(), Spalte50 = random.Next(100, 10000).ToString() }); } } } }
using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using System; using System.Collections.Generic; using System.Diagnostics; namespace OpenXMLSample { public class Report { public void CreateExcelDoc(string fileName) { using (SpreadsheetDocument document = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook)) { WorkbookPart workbookPart = document.AddWorkbookPart(); workbookPart.Workbook = new Workbook(); WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>(); worksheetPart.Worksheet = new Worksheet(); Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets()); Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Employees" }; sheets.Append(sheet); workbookPart.Workbook.Save(); List<Employee> employees = Employees.EmployeesList; SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData()); // Constructing header Row row = new Row(); row.Append( ConstructCell("Id", CellValues.String), ConstructCell("Name", CellValues.String), ConstructCell("Birth Date", CellValues.String), ConstructCell("Salary", CellValues.String), ConstructCell("Spalte 05", CellValues.String), ConstructCell("Spalte 06", CellValues.String), ConstructCell("Spalte 07", CellValues.String), ConstructCell("Spalte 08", CellValues.String), ConstructCell("Spalte 09", CellValues.String), ConstructCell("Spalte 10", CellValues.String), ConstructCell("Spalte 11", CellValues.String), ConstructCell("Spalte 12", CellValues.String), ConstructCell("Spalte 13", CellValues.String), ConstructCell("Spalte 14", CellValues.String), ConstructCell("Spalte 15", CellValues.String), ConstructCell("Spalte 16", CellValues.String), ConstructCell("Spalte 17", CellValues.String), ConstructCell("Spalte 18", CellValues.String), ConstructCell("Spalte 19", CellValues.String), ConstructCell("Spalte 20", CellValues.String), ConstructCell("Spalte 21", CellValues.String), ConstructCell("Spalte 22", CellValues.String), ConstructCell("Spalte 23", CellValues.String), ConstructCell("Spalte 24", CellValues.String), ConstructCell("Spalte 25", CellValues.String), ConstructCell("Spalte 26", CellValues.String), ConstructCell("Spalte 27", CellValues.String), ConstructCell("Spalte 28", CellValues.String), ConstructCell("Spalte 29", CellValues.String), ConstructCell("Spalte 30", CellValues.String), ConstructCell("Spalte 31", CellValues.String), ConstructCell("Spalte 32", CellValues.String), ConstructCell("Spalte 33", CellValues.String), ConstructCell("Spalte 34", CellValues.String), ConstructCell("Spalte 35", CellValues.String), ConstructCell("Spalte 36", CellValues.String), ConstructCell("Spalte 37", CellValues.String), ConstructCell("Spalte 38", CellValues.String), ConstructCell("Spalte 39", CellValues.String), ConstructCell("Spalte 40", CellValues.String), ConstructCell("Spalte 41", CellValues.String), ConstructCell("Spalte 42", CellValues.String), ConstructCell("Spalte 43", CellValues.String), ConstructCell("Spalte 44", CellValues.String), ConstructCell("Spalte 45", CellValues.String), ConstructCell("Spalte 46", CellValues.String), ConstructCell("Spalte 47", CellValues.String), ConstructCell("Spalte 48", CellValues.String), ConstructCell("Spalte 49", CellValues.String), ConstructCell("Spalte 50", CellValues.String) ); // Insert the header row to the Sheet Data sheetData.AppendChild(row); Stopwatch sw = new Stopwatch(); sw.Start(); // Inserting each employee foreach (var employee in employees) { row = new Row(); row.Append( ConstructCell(employee.Id.ToString(), CellValues.Number), ConstructCell(employee.Name, CellValues.String), ConstructCell(employee.DOB.ToString("yyyy/MM/dd"), CellValues.String), ConstructCell(employee.Salary.ToString(), CellValues.Number), ConstructCell(employee.Spalte05, CellValues.String), ConstructCell(employee.Spalte06, CellValues.String), ConstructCell(employee.Spalte07, CellValues.String), ConstructCell(employee.Spalte08, CellValues.String), ConstructCell(employee.Spalte09, CellValues.String), ConstructCell(employee.Spalte10, CellValues.String), ConstructCell(employee.Spalte11, CellValues.String), ConstructCell(employee.Spalte12, CellValues.String), ConstructCell(employee.Spalte13, CellValues.String), ConstructCell(employee.Spalte14, CellValues.String), ConstructCell(employee.Spalte15, CellValues.String), ConstructCell(employee.Spalte16, CellValues.String), ConstructCell(employee.Spalte17, CellValues.String), ConstructCell(employee.Spalte18, CellValues.String), ConstructCell(employee.Spalte19, CellValues.String), ConstructCell(employee.Spalte20, CellValues.String), ConstructCell(employee.Spalte21, CellValues.String), ConstructCell(employee.Spalte22, CellValues.String), ConstructCell(employee.Spalte23, CellValues.String), ConstructCell(employee.Spalte24, CellValues.String), ConstructCell(employee.Spalte25, CellValues.String), ConstructCell(employee.Spalte26, CellValues.String), ConstructCell(employee.Spalte27, CellValues.String), ConstructCell(employee.Spalte28, CellValues.String), ConstructCell(employee.Spalte29, CellValues.String), ConstructCell(employee.Spalte30, CellValues.String), ConstructCell(employee.Spalte31, CellValues.String), ConstructCell(employee.Spalte32, CellValues.String), ConstructCell(employee.Spalte33, CellValues.String), ConstructCell(employee.Spalte34, CellValues.String), ConstructCell(employee.Spalte35, CellValues.String), ConstructCell(employee.Spalte36, CellValues.String), ConstructCell(employee.Spalte37, CellValues.String), ConstructCell(employee.Spalte38, CellValues.String), ConstructCell(employee.Spalte39, CellValues.String), ConstructCell(employee.Spalte40, CellValues.String), ConstructCell(employee.Spalte41, CellValues.String), ConstructCell(employee.Spalte42, CellValues.String), ConstructCell(employee.Spalte43, CellValues.String), ConstructCell(employee.Spalte44, CellValues.String), ConstructCell(employee.Spalte45, CellValues.String), ConstructCell(employee.Spalte46, CellValues.String), ConstructCell(employee.Spalte47, CellValues.String), ConstructCell(employee.Spalte48, CellValues.String), ConstructCell(employee.Spalte49, CellValues.String), ConstructCell(employee.Spalte50, CellValues.String) ); sheetData.AppendChild(row); } worksheetPart.Worksheet.Save(); sw.Stop(); Console.WriteLine($"Export (1)-Dauer {sw.ElapsedMilliseconds} ms"); } } private Cell ConstructCell(string value, CellValues dataType) { return new Cell() { CellValue = new CellValue(value), DataType = new EnumValue<CellValues>(dataType) }; } } }
Gruß
Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP
Mittwoch, 28. November 2018 08:25 -
Hi Stefan,
und welche Zeiten werden mit Deiner Demo erreicht?--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und TricksMittwoch, 28. November 2018 08:43 -
Hallo Peter,
debug: 1570ms
release: 931ms
Das ist aber wahrscheinlich auch pc-abhängig. Ich wollte schnell eine Demo zum Vergleich aus den Demos von euch und meiner erstellen, bekomme aber folgenden Fehler (bei dem Code von Stefan Falz):
System.Data.OleDb.OleDbException: "The INSERT INTO statement contains the following unknown field name: 'ID'. Make sure you have typed the name correctly, and try the operation again."
...dauert also noch ein bisschen :)
Zum Vergleich, deine Demo (Module Module45) läuft hier mit:
debug: 4500ms
release: 4340ms
relativ gleich lang...
Gruß
Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP
- Bearbeitet Stefan Krömer Mittwoch, 28. November 2018 09:20
Mittwoch, 28. November 2018 09:10 -
Hallo Stefan,
die Spalten müssen in der Exceldatei in der Tabelle1 vorhandein sein. Das hatte ich jetzt nicht im Code gemacht.
Die Exceldatei findest du hier.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, RemotesupportMittwoch, 28. November 2018 09:20Moderator -
Hallo Stefan,
war klar, das ich etwas vergessen habe... Danke!
Ich habe jetzt mal auf die schnelle (2 Durchläufe) die Demos getestet:
OpenXml:
debug= 1570ms
release= 930ms
Modul45 (Peter):
debug= 4500ms
release= 4340ms
WriteExcel (Stefan Falz):
debug= 4010ms
release= 3700ms
WriteExcel2 (Stefan Falz):
debug= 4810ms
release= 4400ms
Gruß
Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP
Mittwoch, 28. November 2018 09:37 -
Hi,
wer es wirklich schnell haben will und nur Daten (ohne Formatierung) auszugeben hat, ist mit csv noch viel schneller, bei mir 59 ms.Imports System.IO Module Module42 Sub Main() Try Dim c As New Demo c.Execute() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.WriteLine("weiter mit Taste") Console.ReadKey() End Sub Friend Class Demo Private fileName As String = "c:\temp\x.csv" Friend Sub Execute() Dim sw As New Stopwatch sw.Start() Using wrt As New StreamWriter(fileName) For i = 1 To 1000 For k = 1 To 50 wrt.Write($"Zelle {i} {k}") Next wrt.WriteLine() Next End Using sw.Stop() Console.WriteLine($"Export-Dauer {sw.ElapsedMilliseconds} ms") End Sub End Class End Module
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und TricksMittwoch, 28. November 2018 10:50