Jak mogę wyeksportować DataTabledo Excela w C #? Używam Windows Forms. DataTableJest związany z DataGridViewkontrolą. Muszę wyeksportować rekordy DataTabledo programu Excel.
Najłatwiejszym sposobem jest wykonanie zagnieżdżonej pętli foreach na elementach i elementach podrzędnych.
Saeid Yazdani
UWAGA: Jeśli próbujesz przekazać wartości z tabeli danych do obiektu, a następnie do programu Excel, powinieneś również zająć się obsługą błędów typu danych. Na przykład Guids zabije twoje zadanie za pomocą wyjątku HRESULT: 0x800A03EC. Jednym z obejść bez testowania typów danych jest użycie "ToString ()" podczas wypełniania obiektu. Program Excel sam skonwertuje liczby z powrotem do formatu liczb. FlashTrev as rozwiązał powiązany problem z datą / godziną.
Dodanie ~ 6 MB przywoływanych bibliotek nie spowodowałoby, że aplikacja byłaby trochę ciężka?
ʞᴉɯ
4
Dobre pytanie @MicheleVirgilio. Nie przeprowadziłem żadnych testów, aby określić wpływ. Ale bez względu na to, co jest warte, nie przeszkadzało mi to w żadnym z projektów, z których go korzystałem, w rzeczywistości nie mogę powiedzieć, że kiedykolwiek to zauważyłem.
hmqcnoesy
Ten kod zwrócił mi Excel z pojedynczą kolumną z wartościąClosedXML.Excel.XLWorkbook
To pułapka,
80
Wypróbuj prosty kod, aby przekonwertować DataTable do pliku Excela jako csv:
Cóż za doskonała odpowiedź, stary. Nie mam możliwości, aby udzielić więcej niż jednego głosu pozytywnego na twoją odpowiedź, w przeciwnym razie mógłbym oddać nawet więcej niż 100 głosów pozytywnych.
Ashok kumar
2
@Cuong Le - jeśli w komórce są dwa przecinki, problem wystąpi przy „string.Join („, ”)”
suneel ranga
@Cuong Le, gdzie będzie "excel.csv"lokalizacja?
Jogi
2
@suneelranga - Jeśli komórka (tj. w row.ItemArray) zawiera ,(przecinek), to zgodnie ze standardem CSV komórka ta powinna zostać otoczona cudzysłowami, ","a następnie pojawić się w pliku jak zwykle. A więc tak - spowoduje to problem, ponieważ ten kod nie wykrywa ,i nie stosuje cudzysłowów.
Tom Leys
1
@ Si8 po zapisaniu możesz wykonać Process.Start (Twój plik) i otworzy go dla nich.
Wydaje
40
Elegancką opcją jest napisanie metody rozszerzającej (patrz poniżej) dla klasy DataTable platformy .net.
Tę metodę rozszerzenia można wywołać w następujący sposób:
using System;
using System.Collections.Generic;
using System.Linq;
using Excel=Microsoft.Office.Interop.Excel;
using System.Data;
using System.Data.OleDb;DataTable dt;// fill table data in dt here ...// export DataTable to excel// save excel file without ever making it visible if filepath is given// don't save excel file, just make it visible if no filepath is given
dt.ExportToExcel(ExcelFilePath);
Metoda rozszerzenia dla klasy DataTable:
publicstaticclassMy_DataTable_Extensions{// Export DataTable into an excel file with field names in the header line// - Save excel file without ever making it visible if filepath is given// - Don't save excel file, just make it visible if no filepath is givenpublicstaticvoidExportToExcel(thisDataTable tbl,string excelFilePath =null){try{if(tbl ==null|| tbl.Columns.Count==0)thrownewException("ExportToExcel: Null or empty input table!\n");// load excel, and create a new workbookvar excelApp =newExcel.Application();
excelApp.Workbooks.Add();// single worksheetExcel._Worksheet workSheet = excelApp.ActiveSheet;// column headingsfor(var i =0; i < tbl.Columns.Count; i++){
workSheet.Cells[1, i +1]= tbl.Columns[i].ColumnName;}// rowsfor(var i =0; i < tbl.Rows.Count; i++){// to do: format datetime values before printingfor(var j =0; j < tbl.Columns.Count; j++){
workSheet.Cells[i +2, j +1]= tbl.Rows[i][j];}}// check file pathif(!string.IsNullOrEmpty(excelFilePath)){try{
workSheet.SaveAs(excelFilePath);
excelApp.Quit();MessageBox.Show("Excel file saved!");}catch(Exception ex){thrownewException("ExportToExcel: Excel file could not be saved! Check filepath.\n"+ ex.Message);}}else{// no file path is given
excelApp.Visible=true;}}catch(Exception ex){thrownewException("ExportToExcel: \n"+ ex.Message);}}}
@ alex.pulver to również nie działa, gdy próbowałem go użyć na serwerze. Warto wspomnieć.
Si8
To zadziała, ale działa wolno. Najlepiej skopiować do schowka i wkleić do programu Excel. Jeśli pracujesz na więcej niż 1000 rekordów, zajmie to trochę czasu.
Alex M
25
Rozwiązanie oparte na artykule tuncalik (dzięki za pomysł), ale w przypadku dużych stołów działa znacznie szybciej (i jest trochę mniej przejrzyste).
publicstaticclassMy_DataTable_Extensions{/// <summary>/// Export DataTable to Excel file/// </summary>/// <param name="DataTable">Source DataTable</param>/// <param name="ExcelFilePath">Path to result file name</param>publicstaticvoidExportToExcel(thisSystem.Data.DataTableDataTable,stringExcelFilePath=null){try{intColumnsCount;if(DataTable==null||(ColumnsCount=DataTable.Columns.Count)==0)thrownewException("ExportToExcel: Null or empty input table!\n");// load excel, and create a new workbookMicrosoft.Office.Interop.Excel.ApplicationExcel=newMicrosoft.Office.Interop.Excel.Application();Excel.Workbooks.Add();// single worksheetMicrosoft.Office.Interop.Excel._WorksheetWorksheet=Excel.ActiveSheet;object[]Header=newobject[ColumnsCount];// column headings for(int i =0; i <ColumnsCount; i++)Header[i]=DataTable.Columns[i].ColumnName;Microsoft.Office.Interop.Excel.RangeHeaderRange=Worksheet.get_Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[1,1]),(Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[1,ColumnsCount]));HeaderRange.Value=Header;HeaderRange.Interior.Color=System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);HeaderRange.Font.Bold=true;// DataCellsintRowsCount=DataTable.Rows.Count;object[,]Cells=newobject[RowsCount,ColumnsCount];for(int j =0; j <RowsCount; j++)for(int i =0; i <ColumnsCount; i++)Cells[j, i]=DataTable.Rows[j][i];Worksheet.get_Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[2,1]),(Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[RowsCount+1,ColumnsCount])).Value=Cells;// check fielpathif(ExcelFilePath!=null&&ExcelFilePath!=""){try{Worksheet.SaveAs(ExcelFilePath);Excel.Quit();System.Windows.MessageBox.Show("Excel file saved!");}catch(Exception ex){thrownewException("ExportToExcel: Excel file could not be saved! Check filepath.\n"+ ex.Message);}}else// no filepath is given{Excel.Visible=true;}}catch(Exception ex){thrownewException("ExportToExcel: \n"+ ex.Message);}}}
Odpowiedź tuncalika zajęła mi prawie minutę, to jest 1 sekunda, jeśli trwa to długo ... Właściwie byłem zaskoczony.
Wilsu
2
To najszybsza próbka, jaką próbowałem, świetna robota. Musiałem użyć Marshal, aby zwolnić plik po. Excel.Quit(); Marshal.FinalReleaseComObject(Worksheet); Marshal.FinalReleaseComObject(HeaderRange); Marshal.FinalReleaseComObject(Excel);
Dave Kelly
Czy wymaga zainstalowania pakietu Office?
Parshuram Kalvikatte
W przeciwnym razie działa doskonale, ale mój kolor tła nagłówka jest ustawiony na czarny zawsze podczas korzystania z tego rozwiązania w aplikacji konsolowej. Jaki może być powód?
Zaveed Abbasi
15
Wypróbuj tę funkcję i przekaż datę i ścieżkę do pliku, do którego chcesz wyeksportować
publicvoidCreateCSVFile(refDataTable dt,string strFilePath){try{// Create the CSV file to which grid data will be exported.StreamWriter sw =newStreamWriter(strFilePath,false);// First we will write the headers.//DataTable dt = m_dsProducts.Tables[0];int iColCount = dt.Columns.Count;for(int i =0; i < iColCount; i++){
sw.Write(dt.Columns[i]);if(i < iColCount -1){
sw.Write(",");}}
sw.Write(sw.NewLine);// Now write all the rows.foreach(DataRow dr in dt.Rows){for(int i =0; i < iColCount; i++){if(!Convert.IsDBNull(dr[i])){
sw.Write(dr[i].ToString());}if(i < iColCount -1){
sw.Write(",");}}
sw.Write(sw.NewLine);}
sw.Close();}catch(Exception ex){throw ex;}}
Zauważ, że tak naprawdę nie użyje to komórek tabeli w dokumencie Excela, zamiast tego wszystko dla każdego wiersza zostanie wydrukowane w pierwszej komórce każdego wiersza.
Banshee
@Banshee Nie, program Excel w pełni rozumie pliki CSV.
NickG,
Nie działa również z moim programem Excel. Dane każdego wiersza znajdują się w pierwszej komórce.
Mitulát báti
5
Najlepszy i najłatwiejszy sposób
privatevoid exportToExcel(DataTable dt){/*Set up work book, work sheets, and excel application*/Microsoft.Office.Interop.Excel.Application oexcel =newMicrosoft.Office.Interop.Excel.Application();try{string path =AppDomain.CurrentDomain.BaseDirectory;object misValue =System.Reflection.Missing.Value;Microsoft.Office.Interop.Excel.Workbook obook = oexcel.Workbooks.Add(misValue);Microsoft.Office.Interop.Excel.Worksheet osheet =newMicrosoft.Office.Interop.Excel.Worksheet();// obook.Worksheets.Add(misValue);
osheet =(Microsoft.Office.Interop.Excel.Worksheet)obook.Sheets["Sheet1"];int colIndex =0;int rowIndex =1;foreach(DataColumn dc in dt.Columns){
colIndex++;
osheet.Cells[1, colIndex]= dc.ColumnName;}foreach(DataRow dr in dt.Rows){
rowIndex++;
colIndex =0;foreach(DataColumn dc in dt.Columns){
colIndex++;
osheet.Cells[rowIndex, colIndex]= dr[dc.ColumnName];}}
osheet.Columns.AutoFit();string filepath ="C:\\Temp\\Book1";//Release and terminate excel
obook.SaveAs(filepath);
obook.Close();
oexcel.Quit();
releaseObject(osheet);
releaseObject(obook);
releaseObject(oexcel);
GC.Collect();}catch(Exception ex){
oexcel.Quit();
log.AddToErrorLog(ex,this.Name);}}
(proszę być tutaj), jeśli istnieje więcej niż jeden otwarty plik Excela, czy ta funkcja zwalniająca niszczy je wszystkie, czy tylko ten przekazany jako parametr?
Elliott Addi
1
Excel Interop:
Ta metoda zapobiega zamianie dat z dd-mm-rrrr na mm-dd-rrrr
publicboolDataTableToExcelFile(DataTable dt,string targetFile){constbool dontSave =false;bool success =true;//Exit if there is no rows to exportif(dt.Rows.Count==0)returnfalse;object misValue =System.Reflection.Missing.Value;List<int> dateColIndex =newList<int>();Excel.Application excelApp =newExcel.Application();Excel.Workbook excelWorkBook = excelApp.Workbooks.Add(misValue);Excel.Worksheet excelWorkSheet = excelWorkBook.Sheets("sheet1");//Iterate through the DataTable and populate the Excel work sheettry{for(int i =-1; i <= dt.Rows.Count-1; i++){for(int j =0; j <= dt.Columns.Count-1; j++){if(i <0){//Take special care with Date columnsif(dt.Columns(j).DataTypeistypeof(DateTime)){
excelWorkSheet.Cells(1, j +1).EntireColumn.NumberFormat="d-MMM-yyyy;@";
dateColIndex.Add(j);}//else if ... Feel free to add more Formatselse{//Otherwise Format the column as text
excelWorkSheet.Cells(1, j +1).EntireColumn.NumberFormat="@";}
excelWorkSheet.Cells(1, j +1)= dt.Columns(j).Caption;}elseif(dateColIndex.IndexOf(j)>-1){
excelWorkSheet.Cells(i +2, j +1)=Convert.ToDateTime(dt.Rows(i).ItemArray(j)).ToString("d-MMM-yyyy");}else{
excelWorkSheet.Cells(i +2, j +1)= dt.Rows(i).ItemArray(j).ToString();}}}//Add Autofilters to the Excel work sheet
excelWorkSheet.Cells.AutoFilter(1,Type.Missing,Excel.XlAutoFilterOperator.xlAnd,Type.Missing,true);//Autofit columns for neatness
excelWorkSheet.Columns.AutoFit();if(File.Exists(exportFile))File.Delete(exportFile);
excelWorkSheet.SaveAs(exportFile);}catch{
success =false;}finally{//Do this irrespective of whether there was an exception or not.
excelWorkBook.Close(dontSave);
excelApp.Quit();
releaseObject(excelWorkSheet);
releaseObject(excelWorkBook);
releaseObject(excelApp);}return success;}
Jeśli nie obchodzi Cię odwracanie dat, użyj linku zobacz, który pokazuje, jak wypełnić wszystkie komórki w arkuszu kalkulacyjnym Excel w jednym wierszu kodu:
Wystarczy skorzystać z biblioteki CloseMXL.Excel . Jest to łatwe i dość szybkie.
Klasa
privateDataTable getAllList(){string constr =ConfigurationManager.ConnectionStrings["RConnection"].ConnectionString;
using (SqlConnection con =newSqlConnection(constr)){
using (SqlCommand cmd =newSqlCommand("SELECT EmpId, gender, EmpName, pOnHold FROM Employee WHERE EmpId= '"+AnyVariable+"' ORDER BY EmpName")){
using (SqlDataAdapter da =newSqlDataAdapter()){DataTable dt =newDataTable();
cmd.CommandType=CommandType.Text;
cmd.Connection= con;
da.SelectCommand= cmd;
da.Fill(dt);
dt.Columns[0].ColumnName="Employee Id";
dt.Columns[1].ColumnName="Gender";
dt.Columns[2].ColumnName="Employee Name";
dt.Columns[3].ColumnName="On Hold";return dt;}}}}
Następnie inna metoda, która pobiera zestaw danych
publicDataSet getDataSetExportToExcel(){DataSet ds =newDataSet();DataTable dtEmp =newDataTable("CLOT List");
dtEmp = getAllList();
ds.Tables.Add(dtEmp);
ds.Tables[0].TableName="Employee";//If you which to use Mutliple Tabsreturn ds;}
Teraz możesz kliknąć przycisk zdarzenia
protectedvoid btn_Export_Click(object sender,EventArgs e){DataSet ds = getDataSetExportToExcel();
using (XLWorkbook wb =newXLWorkbook()){
wb.Worksheets.Add(ds);
wb.Style.Alignment.Horizontal=XLAlignmentHorizontalValues.Center;
wb.Style.Font.Bold=true;Response.Clear();Response.Buffer=true;Response.Charset="";Response.ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";Response.AddHeader("content-disposition","attachment;filename=EmployeeonHoldList.xlsx");
using (MemoryStreamMyMemoryStream=newMemoryStream()){
wb.SaveAs(MyMemoryStream);MyMemoryStream.WriteTo(Response.OutputStream);Response.Flush();Response.End();}}}
Możesz skorzystać z mojej biblioteki SwiftExcel . Jest to szczególnie dobre, gdy występuje wydajność i niskie zużycie pamięci, ponieważ zapisuje dane bezpośrednio do pliku:
using (var ew =newExcelWriter("C:\\temp\\test.xlsx")){for(var row =1; row <=100; row++){for(var col =1; col <=10; col++){
ew.Write($"row:{row}-col:{col}", col, row);}}}
Chciałem dodać tę odpowiedź, ponieważ spędziłem dużo czasu szukając szybkiej, niezawodnej metody, aby to zrobić, i nigdzie nie było żadnych pełnych przykładów użycia OpenXMLWriter do tego celu.
Po pierwsze, COM / Interop (którego używa wiele innych odpowiedzi) jest w porządku do tego celu, ale ma pewne wrażliwości. Używam go od dziesięcioleci i jest w większości stabilny, ale wdrażając front-end hurtowni danych dla setek użytkowników, stwierdziłem, że jest on narażony na zbyt wiele problemów w zależności od maszyny i tego, co zrobił użytkownik, więc przełączyłem się na OpenXML. OpenXML DOM jest całkiem dobry do tego celu, ale jest wolniejszy niż używanie OpenXMLWriter. Kiedy dostaniesz się do dużych zbiorów danych (ponad 100 000) z wieloma kolumnami, DOM jest znacznie wolniejszy niż OpenXMLWriter, więc używam tego drugiego. Poniższa metoda zapisuje ponad 420 000 wierszy z ponad 30 polami w mniej niż 30 sekund.
Mam nadzieję, że komentarze są wystarczające, aby poprowadzić każdego przez to, co robi. Jest to uproszczone, ponieważ zapisuje wszystkie wartości do pliku jako ciągi, ale można zaimplementować logikę do zapisywania różnych typów danych (i używać różnych formatów komórek) na podstawie zawartości danych. Możesz również dostosować to do użycia w DataGridView (zamiast DataTable), zmieniając tylko kilka rzeczy (mianowicie pętle przez kolumny / wiersze).
Wymagane jest odwołanie do DocumentFormat.OpenXML (d / l z OpenXML SDK) i WindowsBase.
ImportsDocumentFormat.OpenXmlImportsDocumentFormat.OpenXml.SpreadsheetImportsDocumentFormat.OpenXml.PackagingPublicSubExportToExcelXML(ByRef dt AsDataTable, filename AsString)Dim wbp AsWorkbookPart, wsp AsWorksheetPart'IfthisDataTable has more rows in it than can fit inExcel,throw an exception
If dt.Rows.Count>1048575ThenThrowNewException("The DataTable is too large to export to Excel.")'Delete any previous file of the same name that may exist.File.Delete(filename)'Create an OpenXMLSpreadsheetDocument...Using xls =SpreadsheetDocument.Create(filename,SpreadsheetDocumentType.Workbook)'Add a WorkbookPart to the SpreadsheetDoc, then add a WorksheetPart to the WorkbookPart.
wbp = xls.AddWorkbookPart()
wsp = wbp.AddNewPart(OfWorksheetPart)'Now we need to add the "StyleSheet" to the WorkbookPart(that we just added above).This will allow us to apply formatting to our Cells.'Add the WbStylesPart and the StyleSheet.Dim stp AsWorkbookStylesPart= wbp.AddNewPart(OfWorkbookStylesPart)Dim ss AsNewStylesheet'Create the only two Fonts we're going to use (Regular and Bold).Dim fBold AsNewFont
fBold.Append(NewBold)Dim fnts AsNewFonts
fnts.Append(NewFont)'This creates the default (unmodified, regular) Font. It's added first, so its index is0.
fnts.Append(fBold)'This creates the Bold font. It's added second, so its index is1.'Create the default Fill/Border settings (these have to be here, even though I don't set any custom fills/borders).Dim flls AsNewFillsDim brdrs AsNewBorders
flls.Append(NewFill)
brdrs.Append(NewBorder)'Now I have to add formats (NumberFormat and CellFormat).First, you create a NumberFormat.Thisis basically the pattern of
' the format (i.e."@"forText).For now, I only need a Text format, but I can add more patterns if needed.' I give the format an ID of 164, since 163iswhere the built-inExcel formats end.Dim nbrfmts AsNewNumberingFormats
nbrfmts.Append(NewNumberingFormatWith{.NumberFormatId=164,.FormatCode="@"})'Create the first two CellFormats:Default, which will have an index of 0 and "Header"(Bold/Centered) with an index of 1.Dim cellfmts AsNewCellFormats()
cellfmts.Append(NewCellFormat()With{.FontId=0,.NumberFormatId=164,.FillId=0,.BorderId=0})
cellfmts.Append(NewCellFormat()With{.FontId=1,.NumberFormatId=164,.Alignment=NewAlignment()With{.WrapText=True,.Horizontal=HorizontalAlignmentValues.Center}})'Add all of the Fonts/Fills/Borders/etc to the StyleSheet and add it all to the WorkbookStylesPart.
ss.Append(fnts)
ss.Append(flls)
ss.Append(brdrs)
ss.Append(cellfmts)
ss.NumberingFormats= nbrfmts
stp.Stylesheet= ss
stp.Stylesheet.Save()'Now create an OpenXMLWriter using the WorksheetPart to write the cells to the worksheet.Using oxw AsOpenXmlWriter=OpenXmlWriter.Create(wsp)'Write the start element for the Worksheet and the Columns...
oxw.WriteStartElement(NewWorksheet)
oxw.WriteStartElement(NewColumns())'Now I'm going to loop through the columns in the DataTable...For c AsInteger=0To dt.Columns.Count-1'Now we'll get the width for the column.Todothis, we loop through all of the rows and measure the width of the text
' using the defaultExcelFont(currently Font:CalibriSize:11) and return the largest width (in pixels) to use below.' Why not do this loop below (when I loop through the rows to write the Cells)? Because you can't.You have to
' write the Column XML first before writing the SheetData/Row/Cell XML (I confirmed this by trying it), so there's
' no way (that I'm aware of) to avoid looping through all of the rows twice if you want to AutoFit.'Setup vars we'll use for getting the column widths (below).Dim g =System.Drawing.Graphics.FromHwnd(IntPtr.Zero)Dim fnt =NewSystem.Drawing.Font("Calibri",11)Dim wid AsDouble=0'Get the width of the header (because if this is wider than the widest value, we'll use the header text's width).' I found that adding 2 pixels to the width was necessary to get the column as wide asExcel would make it.Dim tmp AsDouble= g.MeasureString(dt.Columns(c).ColumnName,NewSystem.Drawing.Font(fnt,System.Drawing.FontStyle.Bold)).Width+2'Loop through the rows in the dt and get the width of the value in that row/col. If it's wider than the widest
' width we've encountered thus far, use the new wider width as our basis.ForEach row AsDataRowIn dt.RowsIf tmp > wid Then wid = tmp
tmp = g.MeasureString(row(c).ToString, fnt).WidthNext'Set the column attributes and write it to the file. The Width is set using a formula that converts from pixels to Excel's column width values.Dim oxa AsNewList(OfOpenXmlAttribute)From{NewOpenXmlAttribute("min",Nothing, c +1),NewOpenXmlAttribute("max",Nothing, c +1),NewOpenXmlAttribute("width",Nothing,System.Math.Round((wid -12+5)/7D+1,2))}
oxw.WriteStartElement(NewColumn(), oxa)
oxw.WriteEndElement()Next'CLoseout the Columns collection.
oxw.WriteEndElement()'Write the start element for the SheetData...
oxw.WriteStartElement(NewSheetData)'Write the start element for the Header row.
oxw.WriteStartElement(NewRow)'Loop through the Columnsin the dt.ForEach col AsDataColumnIn dt.Columns'Write a cell for this column's Header.AllHeader cells are written with a DataType of String("str").' I ALSO apply the "Header"CellFormat(StyleIndex1) to all of the HeaderCells.This makes them Bold and Centered.WriteCell(oxw, col.ColumnName,"str",1)Next'Closeout the Header row.
oxw.WriteEndElement()'Loop through all of the rows in the dt...ForEach row AsDataRowIn dt.Rows'Write a StartElementforthis row...
oxw.WriteStartElement(NewRow)'Loop through all of the columns in the dt...For c AsInteger=0To dt.Columns.Count-1'Write a valueinthis row/column to the Excel file. I use the datatype of "String" and the defaultCellFormat/StyleIndex.WriteCell(oxw, row(c).ToString,"str",0)Next'Closeoutthis row.
oxw.WriteEndElement()Next'Closeout the Worksheet and SheetData elements...
oxw.WriteEndElement()
oxw.WriteEndElement()EndUsing'Now we're going to create an OpenXMLWriter using the WorkbookPart(that we created above)...Using oxw AsOpenXmlWriter=OpenXmlWriter.Create(wbp)'Add starting elements for the Workbook and Sheets collection.
oxw.WriteStartElement(NewWorkbook())
oxw.WriteStartElement(NewSheets())'Add the Sheet(name the Sheet after the file name minus the extension).
oxw.WriteElement(NewSheet()With{.Name=Path.GetFileNameWithoutExtension(filename),.SheetId=1,.Id= xls.WorkbookPart.GetIdOfPart(wsp)})'WriteEnd elements for the Workbook/Sheets
oxw.WriteEndElement()
oxw.WriteEndElement()EndUsingEndUsingEndSub'ThisSubis used to write a value to a Cell using OpenXMLWriter.PrivateSubWriteCell(ByRef oxw AsOpenXmlWriter,valueAsString, datatype AsString, style AsUInt32Value)Dim oxa AsNewList(OfOpenXmlAttribute)From{NewOpenXmlAttribute("t",Nothing, datatype),NewOpenXmlAttribute("s",Nothing, style)}
oxw.WriteStartElement(NewCell(), oxa)Ifvalue<>NothingThen oxw.WriteElement(NewCellValue(value))
oxw.WriteEndElement()EndSub
Wielkie dzięki za poświęcenie czasu na tę odpowiedź. Mam klienta, który ma działające rozwiązanie w programie Excel Interop, ale narzeka na jego powolność. Widziałem kilka innych odpowiedzi na pytania, które prowadziły mnie do OpenXML, ale cieszę się, że mam skrót do rozpoczęcia.
Brandon Barkley
1
Nie ma problemu. Nadal używam COM, ale tylko w środowiskach, nad którymi mam pełną kontrolę. Używam tego podejścia OpenXML w aplikacji z kilkuset użytkownikami przez kilka miesięcy i nie miałem żadnych problemów w porównaniu z cotygodniowymi błędami w COM. Przyjrzałem się też rozwiązaniom innych firm, takim jak te wymienione tutaj, ale wolę pisać to samodzielnie, aby było jak najbardziej wydajne.
WATYF
0
Jeśli chodzi o odpowiedź tuncalika , która jest świetna, zwłaszcza jeśli chcesz trochę pobawić się kodem :) ale to jest umieszczanie moich dat w Excelu w formacie amerykańskim, tj. 2 marca 2014 w Wielkiej Brytanii to 02.03.2014, ale w USA 02/03/2014 z pierwszym miesiącem, a następnie dniem tygodnia. Muszę mieć to w formacie brytyjskim. Jakieś pomysły?
Sprawdziłem, czy jest przechowywany w formacie brytyjskim w moim DataTable, a także mój Excel jest ustawiony na Wielką Brytanię, ale z jakiegoś powodu, gdy tworzy dokument Excela, myśli, że jest to USA (czy to dlatego, że Microsoft jest firmą amerykańską :)
Spróbuję poeksperymentować z kodami kulturowymi, ale nie wiem jeszcze, gdzie to umieścić. Próbowałem, ale to nie przyniosło efektu.
ps
Musiałem zmienić jedną linię, aby działała, dodając „obsadę”, jak poniżej
// single worksheetExcel._Worksheet workSheet =(Excel._Worksheet)excelApp.ActiveSheet;
Aktualizacja: Uzyskałem formatowanie dat w Wielkiej Brytanii, konwertując do formatu LongDateTime, ale jest to jedyne obejście.
Stary wątek - ale pomyślałem, że wrzucę tutaj mój kod. Napisałem małą funkcję, aby zapisać tabelę danych w nowym arkuszu programu Excel w określonej ścieżce (lokalizacji). Będziesz także musiał dodać odniesienie do biblioteki Microsoft Excel 14.0.
Użyłem tego do ekstrapolacji sposobu pisania datatable
* uwaga w instrukcjach catch mam odwołanie do klasy statycznej Errorhandler (możesz je zignorować)
using excel =Microsoft.Office.Interop.Excel;
using System.IO;
using System.Data;
using System.Runtime.InteropServices;//class and namespace wrapper is not shown in this example privatevoidWriteToExcel(System.Data.DataTable dt,string location){//instantiate excel objects (application, workbook, worksheets)
excel.ApplicationXlObj=new excel.Application();XlObj.Visible=false;
excel._WorkbookWbObj=(excel.Workbook)(XlObj.Workbooks.Add(""));
excel._WorksheetWsObj=(excel.Worksheet)WbObj.ActiveSheet;//run through datatable and assign cells to values of datatabletry{int row =1;int col =1;foreach(DataColumn column in dt.Columns){//adding columnsWsObj.Cells[row, col]= column.ColumnName;
col++;}//reset column and row variables
col =1;
row++;for(int i =0; i < dt.Rows.Count; i++){//adding dataforeach(var cell in dt.Rows[i].ItemArray){WsObj.Cells[row, col]= cell;
col++;}
col =1;
row++;}WbObj.SaveAs(location);}catch(COMException x){ErrorHandler.Handle(x);}catch(Exception ex){ErrorHandler.Handle(ex);}finally{WbObj.Close();}}
Działa to dobrze, jednak nigdy później nie zabijesz procesów Excela, więc sugeruję dodanie tego, zastępując SaveAslinię tak, jak jest tutaj: 'XlObj.DisplayAlerts = false; WbObj.SaveAs (lokalizacja); WbObj.Close (); XlObj.Quit (); Marshal.ReleaseComObject (WsObj); Marshal.ReleaseComObject (WbObj); Marshal.ReleaseComObject (XlObj); ” Aby użyć tej Marshal.ReleaseComObjectmetody, dodaj using System.Runtime.InteropServiceszespół do projektu.
GrammatonCleric
0
Jednym ze sposobów byłoby użycie ACE OLEDB Provider (zobacz także parametry połączenia dla Excela ). Oczywiście musiałbyś mieć zainstalowanego i zarejestrowanego dostawcę. Powinieneś go mieć, jeśli masz zainstalowany program Excel, ale jest to coś, co musisz wziąć pod uwagę podczas wdrażania aplikacji.
Oto przykład wywołania metody pomocnika z ExportHelper:ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
Pomocnik do eksportu do pliku Excel za pomocą ACE OLEDB:
publicclassExportHelper{privateconststringExcelOleDbConnectionStringTemplate="Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=YES\";";/// <summary>/// Creates the Excel file from items in DataTable and writes them to specified output file./// </summary>publicstaticvoidCreateXlsFromDataTable(DataTable dataTable,string fullFilePath){string createTableWithHeaderScript =GenerateCreateTableCommand(dataTable);
using (var conn =newOleDbConnection(String.Format(ExcelOleDbConnectionStringTemplate, fullFilePath))){if(conn.State!=ConnectionState.Open){
conn.Open();}OleDbCommand cmd =newOleDbCommand(createTableWithHeaderScript, conn);
cmd.ExecuteNonQuery();foreach(DataRow dataExportRow in dataTable.Rows){AddNewRow(conn, dataExportRow);}}}privatestaticvoidAddNewRow(OleDbConnection conn,DataRow dataRow){string insertCmd =GenerateInsertRowCommand(dataRow);
using (OleDbCommand cmd =newOleDbCommand(insertCmd, conn)){AddParametersWithValue(cmd, dataRow);
cmd.ExecuteNonQuery();}}/// <summary>/// Generates the insert row command./// </summary>privatestaticstringGenerateInsertRowCommand(DataRow dataRow){var stringBuilder =newStringBuilder();var columns = dataRow.Table.Columns.Cast<DataColumn>().ToList();var columnNamesCommaSeparated =string.Join(",", columns.Select(x => x.Caption));var questionmarkCommaSeparated =string.Join(",", columns.Select(x =>"?"));
stringBuilder.AppendFormat("INSERT INTO [{0}] (", dataRow.Table.TableName);
stringBuilder.Append(columnNamesCommaSeparated);
stringBuilder.Append(") VALUES(");
stringBuilder.Append(questionmarkCommaSeparated);
stringBuilder.Append(")");return stringBuilder.ToString();}/// <summary>/// Adds the parameters with value./// </summary>privatestaticvoidAddParametersWithValue(OleDbCommand cmd,DataRow dataRow){var paramNumber =1;for(int i =0; i <= dataRow.Table.Columns.Count-1; i++){if(!ReferenceEquals(dataRow.Table.Columns[i].DataType,typeof(int))&&!ReferenceEquals(dataRow.Table.Columns[i].DataType,typeof(decimal))){
cmd.Parameters.AddWithValue("@p"+ paramNumber, dataRow[i].ToString().Replace("'","''"));}else{objectvalue=GetParameterValue(dataRow[i]);OleDbParameter parameter = cmd.Parameters.AddWithValue("@p"+ paramNumber,value);if(valueisdecimal){
parameter.OleDbType=OleDbType.Currency;}}
paramNumber = paramNumber +1;}}/// <summary>/// Gets the formatted value for the OleDbParameter./// </summary>privatestaticobjectGetParameterValue(objectvalue){if(valueisstring){returnvalue.ToString().Replace("'","''");}returnvalue;}privatestaticstringGenerateCreateTableCommand(DataTable tableDefination){StringBuilder stringBuilder =newStringBuilder();bool firstcol =true;
stringBuilder.AppendFormat("CREATE TABLE [{0}] (", tableDefination.TableName);foreach(DataColumn tableColumn in tableDefination.Columns){if(!firstcol){
stringBuilder.Append(", ");}
firstcol =false;string columnDataType ="CHAR(255)";switch(tableColumn.DataType.Name){case"String":
columnDataType ="CHAR(255)";break;case"Int32":
columnDataType ="INTEGER";break;case"Decimal":// Use currency instead of decimal because of bug described at // http://social.msdn.microsoft.com/Forums/vstudio/en-US/5d6248a5-ef00-4f46-be9d-853207656bcc/localization-trouble-with-oledbparameter-and-decimal?forum=csharpgeneral
columnDataType ="CURRENCY";break;}
stringBuilder.AppendFormat("{0} {1}", tableColumn.ColumnName, columnDataType);}
stringBuilder.Append(")");return stringBuilder.ToString();}}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using excel =Microsoft.Office.Interop.Excel;
using EL =ExcelLibrary.SpreadSheet;
using System.Drawing;
using System.Collections;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace _basic
{publicclassExcelProcesser{publicvoidWriteToExcel(System.Data.DataTable dt){
excel.ApplicationXlObj=new excel.Application();XlObj.Visible=false;
excel._WorkbookWbObj=(excel.Workbook)(XlObj.Workbooks.Add(""));
excel._WorksheetWsObj=(excel.Worksheet)WbObj.ActiveSheet;object misValue =System.Reflection.Missing.Value;try{int row =1;int col =1;foreach(DataColumn column in dt.Columns){//adding columnsWsObj.Cells[row, col]= column.ColumnName;
col++;}//reset column and row variables
col =1;
row++;for(int i =0; i < dt.Rows.Count; i++){//adding dataforeach(var cell in dt.Rows[i].ItemArray){WsObj.Cells[row, col]= cell;
col++;}
col =1;
row++;}WbObj.SaveAs(fileFullName, excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);}catch(Exception ex){MessageBox.Show(ex.Message);}finally{WbObj.Close(true, misValue, misValue);}}}
To rozwiązanie polega w zasadzie na wypychaniu List<Object>danych do Excela, wykorzystuje DataTable do osiągnięcia tego, zaimplementowałem metodę rozszerzającą, więc zasadniczo potrzebne są dwie rzeczy. 1. Metoda rozszerzająca.
publicstaticclassReportHelper{publicstaticstringToExcel<T>(thisIList<T> data){PropertyDescriptorCollection properties =TypeDescriptor.GetProperties(typeof(T));DataTable table =newDataTable();foreach(PropertyDescriptor prop in properties){//table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);if(prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)]!=null){
table.Columns.Add(GetColumnHeader(prop),Nullable.GetUnderlyingType(prop.PropertyType)?? prop.PropertyType);}}//So it seems like when there is only one row of data the headers do not appear//so adding a dummy blank row which fixed the issues//Add a blank Row - Issue # 1471DataRow blankRow = table.NewRow();
table.Rows.Add(blankRow);foreach(T item in data){DataRow row = table.NewRow();foreach(PropertyDescriptor prop in properties)//row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;if(prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)]!=null){
row[GetColumnHeader(prop)]= prop.GetValue(item)??DBNull.Value;}
table.Rows.Add(row);}
table.TableName="Results";var filePath =System.IO.Path.GetTempPath()+"\\"+System.Guid.NewGuid().ToString()+".xls";
table.WriteXml(filePath);return filePath;}privatestaticstringGetColumnHeader(PropertyDescriptor prop){return((FGMS.Entity.Extensions.ReportHeaderAttribute)(prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)])).ReportHeaderText;}}
Udekoruj swoje klasy DTO atrybutem [ReportHeaderAttribute("Column Name")]
Wszystko, co ma być kolumną w Excelu, musi być ozdobione [ReportHeaderAttribute("Column Name")]
Wtedy po prostu
Var userList =Service.GetUsers()//Returns List of UserDTO;var excelFilePath = userList.ToExcel();HttpResponseMessage result =newHttpResponseMessage(HttpStatusCode.OK);var stream =newFileStream(excelFilePath,FileMode.Open);
result.Content=newStreamContent(stream);
result.Content.Headers.ContentType=newMediaTypeHeaderValue("application/vnd.ms-excel");
result.Content.Headers.ContentDisposition=newContentDispositionHeaderValue("attachment"){FileName="UserList.xls"};return result;
a jeśli operator nie chce tworzyć DTO dla każdego stołu, z którym będzie to robił? Na przykład każdy z moich 1 tysięcy tabel to robi. Dodawanie atrybutu nagłówka raportu nie odbywa się w locie - dużo tam kodowania, a nawet przed rozpoczęciem pracy nad prawdziwą pracą. Nie powalając twojego rozwiązania - po prostu wskazując, że zasada lenistwa nie jest tutaj wykorzystywana, ponieważ to rozwiązanie dodaje krok tworzenia dto, a następnie kompilacji. Powinienem powiedzieć - podoba mi się, że użyłeś generyków.
Ken
0
Aby wyeksportować dane do programu Excel, możesz skorzystać z biblioteki ClosedXML.Report ( https://github.com/ClosedXML/ClosedXML.Report ). Uwierz mi, to wspaniała biblioteka i łatwa w użyciu dla niej. Biblioteka nie wymaga programu Excel Interop. ClosedXML.Report generuje plik Excela na podstawie szablonu, który można utworzyć w programie Excel przy użyciu dowolnego formatowania. Na przykład:
var template =newXLTemplate(@".\Templates\report.xlsx");
using (var db =newDbDemos()){var cust = db.customers.LoadWith(c => c.Orders).First();
template.AddVariable(cust);
template.Generate();}
template.SaveAs(outputFile);
Private tmr AsSystem.Windows.Forms.TimerPrivateSubTestExcel()HandlesButton1.Click'// Initial data: SQL Server table with 6 columns and 293000 rows.'// Data table holding all dataDim dt AsNewDataTable("F161")'// Create connectionDim conn AsNewSqlConnection("Server=MYSERVER;Database=Test;Trusted_Connection=Yes;")Dim fAdapter AsNewSqlDataAdapterWith{.SelectCommand=NewSqlCommand($"SELECT * FROM dbo.MyTable", conn)}'// Fill DataTable
fAdapter.Fill(dt)'// Create Excel applicationDim xlApp AsNewExcel.ApplicationWith{.Visible=True}'// Temporarily disable screen updating
xlApp.ScreenUpdating=False'// Create brand new workbookDim xlBook AsExcel.Workbook= xlApp.Workbooks.Add()Dim xlSheet AsExcel.Worksheet=DirectCast(xlBook.Sheets(1),Excel.Worksheet)'// Get number of rowsDim rows_count = dt.Rows.Count'// Get number of columnsDim cols_count = dt.Columns.Count'// Here 's the core idea: after receiving data
'// you need to create an array and transfer it to sheet.'// Why array?'// Because it's the fastest way to transfer data to Excel's sheet.'// So, we have two tasks:'// 1) Create array'// 2) Transfer array to sheet'// ========================================================='// TASK 1: Create array'// ========================================================='// In order to create array, we need to know that'// Excel's Rangeobject expects 2-D array whose lower bounds
'// of both dimensions start from 1.'// This means you can't use C# array.'// You need to manually create such array.'// Since we already calculated number of rows and columns,'// we can use these numbers in creating array.Dim arr =Array.CreateInstance(GetType(Object),{rows_count, cols_count},{1,1})'// Fill arrayFor r =0To rows_count -1For c =0To cols_count -1
arr(r +1, c +1)= dt.Rows(r)(c)NextNext'// ========================================================='// TASK 2: Transfer array to sheet'// ========================================================='// Now we need to transfer array to sheet.'// So, how transfer array to sheet fast?'// '// THE FASTEST WAY TO TRANSFER DATA TO SHEET IS TO ASSIGN ARRAY TO RANGE.'// We could, of course, hard-code values, but Resize property'// makes this work a breeze:
xlSheet.Range("A1").Resize.Resize(rows_count, cols_count).Value= arr
'// If we decide to dump data by iterating over array,'// it will take LOTS of time.'// For r = 1 To rows_count'// For c = 1 To cols_count'// xlSheet.Cells(r, c) = arr(r, c)'// Next'// Next'// Here are time results:'// 1) Assigning array to Range: 3 seconds'// 2) Iterating over array: 45 minutes'// Turn updating on
xlApp.ScreenUpdating=True
xlApp =Nothing
xlBook =Nothing
xlSheet =Nothing'// Here we have another problem:'// creating array took lots of memory (about 150 MB).'// Using 'GC.Collect()', by unknown reason, doesn't help here.'// However, if you run GC.Collect() AFTER this procedure is finished'// (say, by pressing another button and calling another procedure),'// then the memory is cleaned up.'// I was wondering how to avoid creating some extra button to just release memory,'// so I came up with the idea to use timer to call GC.'// After 2 seconds GC collects all generations.'// Do not forget to dispose timer since we need it only once.
tmr =NewTimer()AddHandler tmr.Tick,Sub()
GC.Collect()
GC.WaitForPendingFinalizers()
GC.WaitForFullGCComplete()
tmr.Dispose()EndSub
tmr.Interval=TimeSpan.FromSeconds(2).TotalMilliseconds()
tmr.Start()EndSub
publicclassTestObject{publicintCol1{get;set;}publicintCol2{get;set;}publicstringCol3{get;set;}publicDateTimeCol4{get;set;}}[TestMethod]publicvoidLoadFromCollection_MemberList_Test(){///programming/32587834/epplus-loadfromcollection-text-converted-to-number/32590626#32590626varTestObjectList=newList<TestObject>();for(var i =0; i <10; i++)TestObjectList.Add(newTestObject{Col1= i,Col2= i*10,Col3=(i*10)+"E4"});//Create a test filevar fi =newFileInfo(@"c:\temp\LoadFromCollection_MemberList_Test.xlsx");if(fi.Exists)
fi.Delete();
using (var pck =newExcelPackage(fi)){//Do NOT include Col1var mi =typeof(TestObject).GetProperties().Where(pi => pi.Name!="Col1").Select(pi =>(MemberInfo)pi).ToArray();var worksheet = pck.Workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromCollection(TestObjectList,true,TableStyles.Dark1,BindingFlags.Public|BindingFlags.Instance, mi);
pck.Save();}}
Odpowiedzi:
Polecam ClosedXML -
Możesz przekształcić DataTable w arkusz programu Excel z bardzo czytelnym kodem:
Deweloper jest elastyczny i pomocny. Projekt jest aktywnie rozwijany, a dokumentacja znakomita.
źródło
ClosedXML.Excel.XLWorkbook
Wypróbuj prosty kod, aby przekonwertować DataTable do pliku Excela jako csv:
Spowoduje to zapisanie nowego pliku
excel.csv
w bieżącym katalogu roboczym, w którym zazwyczaj znajduje się plik .exe lub skąd go uruchamiasz.źródło
"excel.csv"
lokalizacja?,
(przecinek), to zgodnie ze standardem CSV komórka ta powinna zostać otoczona cudzysłowami,","
a następnie pojawić się w pliku jak zwykle. A więc tak - spowoduje to problem, ponieważ ten kod nie wykrywa,
i nie stosuje cudzysłowów.Elegancką opcją jest napisanie metody rozszerzającej (patrz poniżej) dla klasy DataTable platformy .net.
Tę metodę rozszerzenia można wywołać w następujący sposób:
Metoda rozszerzenia dla klasy DataTable:
źródło
ExcelFilePath != null && ExcelFilePath != ""
może być!String.IsNullOrEmpty(ExcelFilePath)
Rozwiązanie oparte na artykule tuncalik (dzięki za pomysł), ale w przypadku dużych stołów działa znacznie szybciej (i jest trochę mniej przejrzyste).
źródło
Excel.Quit(); Marshal.FinalReleaseComObject(Worksheet); Marshal.FinalReleaseComObject(HeaderRange); Marshal.FinalReleaseComObject(Excel);
Wypróbuj tę funkcję i przekaż datę i ścieżkę do pliku, do którego chcesz wyeksportować
źródło
Najlepszy i najłatwiejszy sposób
źródło
private void releaseObject(object o) { try { while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) { } } catch { } finally { o = null; } }
Excel Interop:
Excel Interop - wydajność i wydajność
CSV:
źródło
Klasa
Następnie inna metoda, która pobiera zestaw danych
Teraz możesz kliknąć przycisk zdarzenia
źródło
Możesz skorzystać z mojej biblioteki SwiftExcel . Jest to szczególnie dobre, gdy występuje wydajność i niskie zużycie pamięci, ponieważ zapisuje dane bezpośrednio do pliku:
Polecenie NuGet do zainstalowania:
źródło
Chciałem dodać tę odpowiedź, ponieważ spędziłem dużo czasu szukając szybkiej, niezawodnej metody, aby to zrobić, i nigdzie nie było żadnych pełnych przykładów użycia OpenXMLWriter do tego celu.
Po pierwsze, COM / Interop (którego używa wiele innych odpowiedzi) jest w porządku do tego celu, ale ma pewne wrażliwości. Używam go od dziesięcioleci i jest w większości stabilny, ale wdrażając front-end hurtowni danych dla setek użytkowników, stwierdziłem, że jest on narażony na zbyt wiele problemów w zależności od maszyny i tego, co zrobił użytkownik, więc przełączyłem się na OpenXML. OpenXML DOM jest całkiem dobry do tego celu, ale jest wolniejszy niż używanie OpenXMLWriter. Kiedy dostaniesz się do dużych zbiorów danych (ponad 100 000) z wieloma kolumnami, DOM jest znacznie wolniejszy niż OpenXMLWriter, więc używam tego drugiego. Poniższa metoda zapisuje ponad 420 000 wierszy z ponad 30 polami w mniej niż 30 sekund.
Mam nadzieję, że komentarze są wystarczające, aby poprowadzić każdego przez to, co robi. Jest to uproszczone, ponieważ zapisuje wszystkie wartości do pliku jako ciągi, ale można zaimplementować logikę do zapisywania różnych typów danych (i używać różnych formatów komórek) na podstawie zawartości danych. Możesz również dostosować to do użycia w DataGridView (zamiast DataTable), zmieniając tylko kilka rzeczy (mianowicie pętle przez kolumny / wiersze).
Wymagane jest odwołanie do DocumentFormat.OpenXML (d / l z OpenXML SDK) i WindowsBase.
źródło
Jeśli chodzi o odpowiedź tuncalika , która jest świetna, zwłaszcza jeśli chcesz trochę pobawić się kodem :) ale to jest umieszczanie moich dat w Excelu w formacie amerykańskim, tj. 2 marca 2014 w Wielkiej Brytanii to 02.03.2014, ale w USA 02/03/2014 z pierwszym miesiącem, a następnie dniem tygodnia. Muszę mieć to w formacie brytyjskim. Jakieś pomysły?
Sprawdziłem, czy jest przechowywany w formacie brytyjskim w moim DataTable, a także mój Excel jest ustawiony na Wielką Brytanię, ale z jakiegoś powodu, gdy tworzy dokument Excela, myśli, że jest to USA (czy to dlatego, że Microsoft jest firmą amerykańską :)
Spróbuję poeksperymentować z kodami kulturowymi, ale nie wiem jeszcze, gdzie to umieścić. Próbowałem, ale to nie przyniosło efektu.
ps
Musiałem zmienić jedną linię, aby działała, dodając „obsadę”, jak poniżej
Aktualizacja: Uzyskałem formatowanie dat w Wielkiej Brytanii, konwertując do formatu LongDateTime, ale jest to jedyne obejście.
Twoje zdrowie.
źródło
Możesz użyć EasyXLS , czyli biblioteki do eksportowania plików Excel.
Sprawdź ten kod:
Zobacz także ten przykład dotyczący eksportowania danych do programu Excel w języku C # .
źródło
Stary wątek - ale pomyślałem, że wrzucę tutaj mój kod. Napisałem małą funkcję, aby zapisać tabelę danych w nowym arkuszu programu Excel w określonej ścieżce (lokalizacji). Będziesz także musiał dodać odniesienie do biblioteki Microsoft Excel 14.0.
Wyciągnąłem z tego wątku pisanie czegokolwiek do Excela - Jak zapisać dane do pliku Excela (.xlsx)
Użyłem tego do ekstrapolacji sposobu pisania datatable
* uwaga w instrukcjach catch mam odwołanie do klasy statycznej Errorhandler (możesz je zignorować)
źródło
SaveAs
linię tak, jak jest tutaj: 'XlObj.DisplayAlerts = false; WbObj.SaveAs (lokalizacja); WbObj.Close (); XlObj.Quit (); Marshal.ReleaseComObject (WsObj); Marshal.ReleaseComObject (WbObj); Marshal.ReleaseComObject (XlObj); ” Aby użyć tejMarshal.ReleaseComObject
metody, dodajusing System.Runtime.InteropServices
zespół do projektu.Jednym ze sposobów byłoby użycie ACE OLEDB Provider (zobacz także parametry połączenia dla Excela ). Oczywiście musiałbyś mieć zainstalowanego i zarejestrowanego dostawcę. Powinieneś go mieć, jeśli masz zainstalowany program Excel, ale jest to coś, co musisz wziąć pod uwagę podczas wdrażania aplikacji.
Oto przykład wywołania metody pomocnika z
ExportHelper
:ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
Pomocnik do eksportu do pliku Excel za pomocą ACE OLEDB:
źródło
użyj następującej klasy
}
źródło
Wszystko, co ma być kolumną w Excelu, musi być ozdobione
[ReportHeaderAttribute("Column Name")]
Wtedy po prostu
źródło
Aby wyeksportować dane do programu Excel, możesz skorzystać z biblioteki ClosedXML.Report ( https://github.com/ClosedXML/ClosedXML.Report ). Uwierz mi, to wspaniała biblioteka i łatwa w użyciu dla niej. Biblioteka nie wymaga programu Excel Interop. ClosedXML.Report generuje plik Excela na podstawie szablonu, który można utworzyć w programie Excel przy użyciu dowolnego formatowania. Na przykład:
źródło
źródło
Czysto przykładowy kod (jeśli mógłby komuś pomóc w pomysłach), na podstawie odpowiedzi Tomasza Wiśniewskiego z tutaj: https://stackoverflow.com/a/21079709/2717521
MainWindow ExportButton:
Klasa ExportToExcel:
źródło
Dzięki pakietowi EPPlus NuGet jest to bardzo łatwe .
Zauważ, że
Col1
NIE ma tego na wyjściu:źródło