Częstym zadaniem, na które natykam się w czasie pracy programisty .NET to integracja z Office-em. Typowym zastosowanie takiej integracji jest export lub import danych do plików Excela dla Pań z księgowości : )
Jednym z problemów podczas integracji jest szybkość importowania i eksportowania danych do z plików Excela.
Problem szybkości tworzenia plików Excel-a widać już przy wielkościach rzędu 1000 wierszy. Jedyną pomocą jest zmienić sposób obsługi integracji z Excelem.
Mam 4 sposoby tworzenia plików Excela (od najgorszych):
- Można stworzyć plik CSV i zmienić mu nazwę na xls lub xlsx (okropne rozwiązanie)
- Można zintegrować się za pomocą bibliotek COM Microsoft.Office.Interop.Excel (działa wolno przy większych ilościach oraz potrzeba zainstalowanego Office-a na produkcji i deweloperce)
- Open XML SDK 2.5 (najprostszy i najszybszy pod względem nauki konfiguracji sposób komunikacji z Excelem)
- Stworzenie czystego pliku, właściwie struktury OpenXML. (ten sposób preferuje. Wydajność jest znakomita. 153 000 wierszy w 4,5 sekundy.
Opisze ostatni sposób na podstawie biblioteki, którą nie dawno znalazłem na CodeProject.
Bibliotekę przetestowałem i działa produkcyjnie. Wszystkie kroki do jej uruchomienia, opisałem poniżej.
Kody do biblioteki są dostępna na github-ie. Należy je ściągnąć, przekompilować i dodać MyExcelExport.dll do swojego projektu.
Efektem wykonaniu poniższych zadań będzie możliwość wczytania danych z DataTable do pliku xlsx. Aplikacja będzie używać szablonu do określenia jakie dane mają być w jakiej kolumnie.
Najpierw tworzymy obiekt pomocniczy, który będzie wydawał kolejne wiersze.
public class ExelData { private int currow; public DataTable ReportData { get; set; } private int MaxRow { get { return this.ReportData.Rows.Count; } } public object this[string name] { get { if (this.currow > this.ReportData.Rows.Count) { return string.Empty; } if (!this.ReportData.Columns.Contains(name)) { return string.Empty; } return this.ReportData.Rows[this.currow - 1][name] + " "; } } public bool Read() { if (this.ReportData == null) { return false; } if (this.currow <= this.MaxRow) { this.currow++; } return this.currow <= this.MaxRow; } }
Klasa ma zadanie wydawać kolejne wiersze aż do momentu gdy nie dojdziemy do końca pliku. Zastosowany tu indekser dostaje na wejściu nazwę kolumny z szablonu. Na tej podstawie szuka wiersza używając pole „currow”.
Nazwa kolumny z szablonu jest tożsama z nazwami kolumn w obiekcie DataTable. To znaczy w szablonie wpisujemy nazwy kolumn z obiektu DataTable.
Powyżej przykład jak wypełnić szablon.
Następnie do projektu dodajemy dwie klasy( Extensions i ExcelWriter). Klasy te są gotowe i znajdują się w kodach źródłowych projektu w solucji MySample. Pamiętajmy o zmianie namespace-ów.
W klasie ExcelWriter należy zmienić typ argumentu metody „Export” na „ExelData” :
public void Export(ExelData dataSource, string filename)
oraz zmienić typ pola „data” na
ExelData data;
W tym momencie rozwiązanie jest gotowe do uruchomienia. Oczywiście trzeba przygotować dane do DataTable oraz szablon.
Przykładowe wywołanie może wyglądać tak:
public static void CreateFile(DataTable reportdata, string fileName, string excelTemplate) { var data = new ExelData { ReportData = reportdata }; new ExcelWriter(excelTemplate).Export(data, fileName); }
Wszystkie dane z „DataTable” będą wstawone w docelowym pliku xlsx.
Tworzenie excela za pomocą Interop wcale nie musi być wolne. Jeśli tworzymy document i zaczynamy wpisywać do niego rekordy wiersz po wierszu to owszem wydajność jest kiepska. Możnazrobić coś takiego:
Excel.Range range = CreateRange(grid, ws);
range.Value2 = arr;
gdzier arr to dwuwymiarowa tablica obiektów.
Dokladnie tak jak piszesz robilem i nie mialem zadawalajacych wynikow. Moze podejde do tematu raz jeszcze. Dzieki za info