Bugün son günlerde urastigim birseyi sizlerle paylasmak istiyorum.
Datagridview dan Excel e veri export etmem gerekiyordu, bunun icin hemen bir Library aradim, FF de arkadasin birisi sagolsun yardimci olmaya calisti.
Ben vermis oldugu linkten NPOI kütüphanesini kesfettim ve kullanmaya basladim.
Ama Iki gün önce farkettimki 10 000 satir lik bir export haddinden fazla (>10 dk) sürüyordu. Halbuki yapilacak olan export nice 10 000 leri yapa bilmeli.
Devam arastirdim bizim servere disaridan erisim kapali sadece Citrix icinden calisiyor ve üstünde Excel bulunuyordu, bende .COM bilesenlerini kullanmaya karar verdim.
Yeni bir test yapip en basit haliyle söyle bir kod olusturdum.
private void btn_export_Click(object sender, EventArgs e) { Excel.Application xlApp; Excel.Workbook xlWorkBook; Excel.Worksheet xlWorkSheet; object misValue = System.Reflection.Missing.Value; xlApp = new Excel.Application(); xlApp.ScreenUpdating = false; xlApp.Calculation = Excel.XlCalculation.xlCalculationManual; xlWorkBook = xlApp.Workbooks.Add(misValue); xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); int ix = 0; int j = 0; //datagridview un baslik sütunünü ekliyelim for (int x = 0; x < dgv_search_result.Columns.Count; x++) { xlWorkSheet.Cells[1, x + 1] = dgv_search_result.Columns[x].HeaderText; } //basliklari kalin yazalim ve yaziyi ortaliyalim xlWorkSheet.get_Range("A1", "T1").Font.Bold = true; xlWorkSheet.get_Range("A1", "T1").VerticalAlignment = Excel.XlVAlign.xlVAlignCenter; //ardindan Datagridview daki satirlari excel dosyamiza yazalim for (ix = 1; ix <= rowcount; ix++) { for (j = 0; j <= dgv_search_result.ColumnCount - 1; j++){ DataGridViewCell cell = dgv_search_result[j, ix - 1]; //10. sutünü Text olarak formatliyalim if(j==10) xlWorkSheet.Cells[ix + 1, j + 1].NumberFormat = "@"; xlWorkSheet.Cells[ix + 1, j + 1] = cell.Value; } } //kayit edelim xlWorkBook.SaveAs(extraction_export.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue); xlWorkBook.Close(true, misValue, misValue); xlApp.Quit(); //objeleri yok edelim releaseObject(xlWorkSheet); releaseObject(xlWorkBook); releaseObject(xlApp); } private void releaseObject(object obj){ try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch (Exception ex) { obj = null; MessageBox.Show("Hata olustu " + ex.ToString()); } finally { GC.Collect(); } }
Bu Npoi yönteminden cok daha hizliydi ama yinede yeterince hizli degildi 10 dk dan fazla sürmesede en az 5 dk sürüyordu 10 000 satir icin.
Bunu dahada hizlandirmam gerekiyordu, Öncelikle yukarki kodda her satiri tek tek ekledigimizden bir güc kaybediyorduk bunu degistirmek icin aramalara girdim.
Ardindan hepsini bir objeye kaydedip birden eklemenin daha dogru olacagini okudum.
Hemen uyguladim söyle bir kod cikti ortaya
private void btn_export_Click(object sender, EventArgs e) { Excel.Application xlApp; Excel.Workbook xlWorkBook; Excel.Worksheet xlWorkSheet; Excel.Sheets excelSheet; Excel.Workbooks excelWorkBooks; object misValue = System.Reflection.Missing.Value; xlApp = new Excel.Application(); excelWorkBooks = xlApp.Workbooks; xlWorkBook = excelWorkBooks.Add(misValue); excelSheet = xlWorkBook.Worksheets; xlWorkSheet = (Excel.Worksheet)excelSheet.get_Item(1); var data = new object[rowcount, columncount]; //basliklari ekliyelim for (int x = 0; x < columncount; x++){ data[0, x] = dgv_search_result.Columns[x].HeaderText; } //basliklari kalin ve sutünun ortasina pozisyonliyalim var boldformat = xlWorkSheet.get_Range("A1", "T1"); var m_objfont = boldformat.Font; m_objfont.Bold = true; var verformat = xlWorkSheet.get_Range("A1", "T1"); verformat.VerticalAlignment = Excel.XlVAlign.xlVAlignCenter; //satirlari objemize ekliyelim for (var row = 1; row < rowcount; row++){ for (var column = 1; column <= columncount; column++){ data[row , column - 1] = dgv_search_result.Rows[row - 1].Cells[column - 1].Value.ToString(); } } //K sütünün Text olarak formatliyalim string endcelltelephone = "K" + rowcount.ToString(); var writeFormat = xlWorkSheet.get_Range("K1", endcelltelephone); writeFormat.NumberFormat = "@"; //Objeyi ekliyecegimiz Range i belirliyelim string endcell = "T" + rowcount.ToString(); var writeR = xlWorkSheet.get_Range("A1", endcell); //objeyi hazirladigimiz range e ekliyelim writeR.Value2 = data; //kayit edelim xlWorkBook.SaveAs(extraction_export.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue); data = null; xlWorkBook.Close(false, misValue, misValue); excelWorkBooks.Close(); xlApp.Quit(); //objeleri yok edelim System.Runtime.InteropServices.Marshal.ReleaseComObject(verformat); System.Runtime.InteropServices.Marshal.ReleaseComObject(boldformat); System.Runtime.InteropServices.Marshal.ReleaseComObject(m_objfont); System.Runtime.InteropServices.Marshal.ReleaseComObject(writeFormat); System.Runtime.InteropServices.Marshal.ReleaseComObject(writeR); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkSheet); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelWorkBooks); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBook); System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp); verformat = null; boldformat = null; m_objfont = null; writeR = null; writeFormat = null; xlWorkSheet = null; excelSheet = null; excelWorkBooks = null; xlWorkBook = null; xlApp = null; //GC calistiralim GC.GetTotalMemory(false); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.GetTotalMemory(true); }
bu yöntem ile 10 000 satiri 10 saniye den az bi zamanda export ede biliyoruz.
Simdi dikkat edilmesi gereken seyleri yazmak istiyorum arkadaslar.
Öncelikle .COM bilesenini kullanmak istiyorsaniz Programi kullandiginiz makinada Excel kurulu olmalidir.
Projenin References bölümünden “Add Reference” e tiklayarak Reference ekleme penceresini aciyoruz. COM sekmesinde sunucuda kayitli Com bilesenlerine ulasa bilirsiniz biz Microsoft Excel 12.0 Object Library yi projemize ekliyoruz. (12 sizde degisik ola bilir, bende Excel 2007 var ondan 12 )
Projemizin basina
using Excel = Microsoft.Office.Interop.Excel;
yaziyoruz.
Ve son olarak ögrenmis oldugum en önemli seylerden birtanesini sizlerle paylasmak istiyorum.
Never use 2 dots with COM objects:
Ben yukarki kodda Excel in kayit ettikden sonra kapanmamasi ve üretilen Excel dosyasinin ici bos görünmesi sorununu yasiyorudm.
Bunu asmanin tek yolu yukardaki kural a uymakdir.
Örnek vermek gerekirse
xlWorkSheet.get_Range("A1", "T1").Font.Bold = true;
bu sekil iken excel kapanmiyor ve ben cildiriyordum. bu satiri böyle düzeltince ve diger satirlarida düzenleyince sorunlar kalkti.
var boldformat = xlWorkSheet.get_Range("A1", "T1"); var m_objfont = boldformat.Font; m_objfont.Bold = true;
gördügünüz gibi tek satir icinde 2 (.) nokta kullanmadik.
Kodumuzun basindada normalde internet örneklerinde bulunan satirlardan fazla satir bulunmakda bunun tek sebebi o kuraldir.
Excel.Application xlApp; Excel.Workbook xlWorkBook; Excel.Worksheet xlWorkSheet; Excel.Sheets excelSheet; Excel.Workbooks excelWorkBooks;
umarim isinize yarar ve benim kadar aramak zorunda kalmassiniz.
Kolay gelsin
8 Comments
Ellerine saglik, excel artik duzgun kapaniyor. Bir de ben soyle birsey buldum, excel objesi ile isim bittikten sonra asagidakini cagiriyorum. Ortalik dumduz oluyor, excel den eser kalmiyor.
private static void KillExcel()
{
try
{
System.Diagnostics.Process[] PROC = System.Diagnostics.Process.GetProcessesByName(“EXCEL”);
foreach (System.Diagnostics.Process PK in PROC)
{
//User excel process always have window name
//COM process do not.
if (PK.MainWindowTitle.Length == 0)
PK.Kill();
}
}
catch
{
throw;
}
}
Window name li olan kismi bilmiyordum sagolasin ekledigin icin deniyecegim, process kill de sorun tüm excell process lerinin kapanmasiydi ondan kullanmamistim.
verileri bir excele yazdırdım diyelım..daha sonra aynı excele tekrar yazdırmak istiyorum yani aynı sayfa yeni sayfa oluşturmucak eskı verilerin yerine yenileri gelıcek .bunu nası yapabilirim. fikriniz varmı.
Merhaba. 46. satırdaki
extraction_export.FileName
ifadesi hata veriyor.
The name ‘extraction_export’ does not exist in the current context
hatasını veriyor.
o bana ait bir degisken, dosya ismi ile degise bilirsiniz.
dgv_search_result – Datagridview ile
rowcount, columncount – Datagridview.rowcount,Datagridview. columncount ile
extraction_export -SaveFileDialog1 ile değiştirdim.
Aşağıdaki 48.satırda
Message=Dosyaya erişilemedi. Aşağıdakilerden birini deneyin:
• Belirtilen klasörün varolduğundan emin olun.
• Dosyayı içeren klasörün salt okunur olmadığından emin olun.
• Dosya adının aşağıdaki karakterlerden herhangi birini içermediğinden emin olun: ? [ ] : | ya da *
• Dosya/yol adının 218 karakterden uzun olmadığından emin olun.
Source=Microsoft Excel
ErrorCode=-2146827284
StackTrace:
konum: Microsoft.Office.Interop.Excel._Workbook.SaveAs(Object Filename, Object FileFormat, Object Password, Object WriteResPassword, Object ReadOnlyRecommended, Object CreateBackup, XlSaveAsAccessMode AccessMode, Object ConflictResolution, Object AddToMru, Object TextCodepage, Object TextVisualLayout, Object Local)
hatasını veriyor.
Eski biçim veya geçersiz kitaplık türü. (HRESULT özel durum döndürdü: 0x80028018 (TYPE_E_INVDATAREAD))
bu hatayı verıyor
suan deniyemiyorum ama surayi bi incele derim:
http://stackoverflow.com/questions/5180713/old-format-or-invalid-type-library-exception-from-hresult-0x80028018-type-e