Wie kann ich eine DataTablein C # nach Excel exportieren ? Ich verwende Windows Forms. Das DataTableist einem DataGridViewSteuerelement zugeordnet. Ich muss Datensätze DataTablenach Excel exportieren .
Am einfachsten ist es, eine verschachtelte foreach-Schleife für Elemente und Unterelemente durchzuführen.
Saeid Yazdani
ANMERKUNG: Wenn Sie versuchen, Werte aus einer Datentabelle an ein Objekt und dann an Excel zu übergeben, sollten Sie auch die Fehlerbehandlung für Datentypen durchführen. Zum Beispiel beenden Guids Ihre Zuweisung mit einer HRESULT: 0x800A03EC-Ausnahme. Eine Möglichkeit, ohne auf Datentypen zu testen, besteht darin, beim Auffüllen Ihres Objekts "ToString ()" zu verwenden. Excel konvertiert Zahlen selbstständig zurück in das Zahlenformat. FlashTrev hat das zugehörige Problem mit Datum und Uhrzeit behoben.
Das Hinzufügen von ~ 6 MB referenzierter Bibliotheken würde die Anwendung nicht wenig schwer machen?
8.
4
Gute Frage @MicheleVirgilio. Ich habe keine Tests durchgeführt, um eine Auswirkung zu quantifizieren. Aber für das, was es wert ist, hat es mich in keinem der Projekte gestört, in denen ich es verwendet habe. Tatsächlich kann ich nicht sagen, dass ich es jemals bemerkt habe.
hmqcnoesy
Dieser Code gab mir ein Excel mit einer einzelnen Spalte mit WertClosedXML.Excel.XLWorkbook
Es ist eine Falle
77
Versuchen Sie es mit einfachem Code, um DataTable in eine Excel-Datei als CSV zu konvertieren:
Dadurch wird eine neue Datei excel.csvin das aktuelle Arbeitsverzeichnis geschrieben, in dem sich normalerweise die EXE- Datei befindet oder von der aus Sie sie starten.
Was für eine hervorragende Antwort, Alter. Ich habe nicht die Möglichkeit, Ihrer Antwort mehr als eine Stimme zu geben, sonst hätte ich sogar mehr als 100 Stimmen abgeben können.
Ashok Kumar
2
@ Cuong Le - Wenn die Zelle zwei Kommas hat, dann wird es ein Problem bei "string.Join (", ")"
suneel ranga
@ Cuong Le wo wird der "excel.csv"Standort sein?
Jogi
2
@suneelranga - Wenn eine Zelle (dh in row.ItemArray) ein ,(Komma ) enthält , sollte diese Zelle nach dem CSV-Standard in Anführungszeichen gesetzt werden ","und dann wie gewohnt in der Datei erscheinen. Also ja - es wird ein Problem verursachen, da dieser Code ,die Anführungszeichen nicht erkennt und anwendet.
Tom Leys
1
@ Si8 einmal gespeichert, können Sie einen Process.Start (Ihre Datei) durchführen und es wird für sie geöffnet. Das ist ungefähr so nah wie möglich, glaube ich.
TimmRH
40
Eine elegante Option ist das Schreiben einer Erweiterungsmethode (siehe unten) für die DataTable-Klasse des .net-Frameworks.
Diese Erweiterungsmethode kann wie folgt aufgerufen werden:
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);
Erweiterungsmethode für die DataTable-Klasse:
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 es funktioniert auch nicht, als ich versuchte, es auf einem Server zu verwenden. Guter Punkt zu erwähnen.
Si8
Das wird funktionieren, aber es ist langsam. Am besten in die Zwischenablage kopieren und in Excel einfügen. Wenn Sie an mehr als 1000 Datensätzen arbeiten, dauert dies eine Weile.
Alex M
25
Die Lösung basiert auf dem Artikel von tuncalik (danke für die Idee), funktioniert aber bei großen Tischen viel schneller (und ist etwas weniger klar).
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);}}}
Die Antwort von tuncalik dauerte fast eine Minute für mich, dies ist bei 1 Sekunde, wenn es lange dauert ... Ich war tatsächlich erschrocken.
Wilsu
2
Dies ist die schnellste Probe, die ich versucht habe, tolle Arbeit. Ich musste Marshal verwenden, um die Datei danach freizugeben. Excel.Quit(); Marshal.FinalReleaseComObject(Worksheet); Marshal.FinalReleaseComObject(HeaderRange); Marshal.FinalReleaseComObject(Excel);
Dave Kelly
Muss Office installiert werden?
Parshuram Kalvikatte
Funktioniert ansonsten einwandfrei, aber meine Hintergrundfarbe für Header Back wird immer auf Schwarz gesetzt, wenn diese Lösung in Konsolenanwendungen verwendet wird. Was könnte der Grund sein?
Zaveed Abbasi
15
Versuchen Sie diese Funktion, und übergeben Sie die Daten- und Dateipfad, in die Sie exportieren möchten
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;}}
Beachten Sie, dass hierdurch die Tabellenzellen im Excel-Dokument nicht wirklich verwendet werden. Stattdessen wird alles für jede Zeile in der ersten Zelle jeder Zeile gedruckt.
(bitte hier sein) Wenn mehr als eine Excel-Datei geöffnet ist, zerstört diese Release-Funktion alle oder nur die als Parameter übergebene?
Elliott Addi
1
Excel Interop:
Diese Methode verhindert, dass Daten von TT-MM-JJJJ auf MM-TT-JJJJ umgedreht werden
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;}
Wenn Sie sich nicht dafür interessieren, dass Daten umgedreht werden, verwenden Sie den Link siehe, der zeigt, wie Sie alle Zellen in der Excel-Tabelle in einer Codezeile füllen:
Nutzen Sie einfach die CloseMXL.Excel- Bibliothek. Es ist einfach und auch ziemlich schnell.
Klasse
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;}}}}
Dann eine andere Methode, die den Datensatz erhält
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;}
Jetzt klicken Sie auf Ereignis
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();}}}
Sie können meine SwiftExcel- Bibliothek verwenden. Dies ist besonders gut, wenn Leistung und geringe Speichernutzung vorhanden sind, da Daten direkt in die Datei geschrieben werden:
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);}}}
Ich wollte diese Antwort hinzufügen, weil ich viel Zeit damit verbracht habe, nach einer schnellen und zuverlässigen Methode zu suchen, und es keine vollständigen Beispiele für die Verwendung von OpenXMLWriter für diesen Zweck gab, die ich finden konnte.
Erstens ist COM / Interop (das von vielen anderen Antworten verwendet wird) für diesen Zweck in Ordnung, leidet jedoch unter einigen Empfindlichkeiten. Ich habe es jahrzehntelang verwendet und es ist größtenteils stabil, aber als ich ein Data Warehouse-Frontend für Hunderte von Benutzern implementierte, stellte ich fest, dass es je nach Computer und dem, was der Benutzer tat, zu vielen Problemen ausgesetzt war, und wechselte zu OpenXML. OpenXML DOM ist für diesen Zweck ziemlich gut, aber langsamer als die Verwendung von OpenXMLWriter. Wenn Sie in große Datenmengen (über 100 KB) mit vielen Spalten gelangen, ist DOM viel langsamer als OpenXMLWriter, daher verwende ich letzteres. Die folgende Methode schreibt 420K + Zeilen mit mehr als 30 Feldern in weniger als 30 Sekunden.
Ich hoffe, die Kommentare reichen aus, um jeden durch das zu führen, was es tut. Dies wird dadurch vereinfacht, dass alle Werte als Zeichenfolgen in die Datei geschrieben werden. Sie können jedoch eine Logik implementieren, um verschiedene Datentypen (und verschiedene Zellenformate) basierend auf dem Inhalt Ihrer Daten zu schreiben. Sie können dies auch für die Verwendung in einer DataGridView (anstelle einer DataTable) anpassen, indem Sie nur einige Dinge ändern (nämlich die Schleifen durch Spalten / Zeilen).
Ein Verweis auf DocumentFormat.OpenXML (d / l mit dem OpenXML SDK) und WindowsBase ist erforderlich.
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
Vielen Dank, dass Sie sich die Zeit für diese Antwort genommen haben. Ich habe einen Kunden, der eine funktionierende Lösung in Excel Interop hat, sich aber darüber beschwert, wie langsam es ist. Ich habe einige andere Antworten auf Fragen gesehen, die mich zu OpenXML führen, bin aber froh, eine Verknüpfung zu den ersten Schritten zu haben.
Brandon Barkley
1
Kein Problem. Ich verwende immer noch COM, aber nur in Umgebungen, über die ich die vollständige Kontrolle habe. Ich verwende diesen OpenXML-Ansatz seit einigen Monaten in einer App mit ein paar hundert Benutzern und hatte im Vergleich zu wöchentlichen Fehlern mit COM keine Probleme. Ich habe mich auch mit Lösungen von Drittanbietern befasst, wie den hier genannten, aber ich schreibe sie lieber selbst, damit ich sie so effizient wie möglich gestalten kann.
WATYF
0
In Bezug auf die Antwort von tuncalik , die großartig ist, besonders wenn Sie ein wenig mit dem Code spielen möchten :) aber es bringt meine Daten in Excel im amerikanischen Format, dh der 2. März 2014 in Großbritannien ist aber der 02.03.2014 in den USA sein 03/02/2014 mit Monat 1, dann Wochentag danach. Ich muss es im britischen Format haben, irgendwelche Ideen bitte?
Ich habe überprüft, ob es in meiner Datentabelle im britischen Format gespeichert ist, und auch mein Excel ist auf Großbritannien eingestellt, aber aus irgendeinem Grund denkt es beim Erstellen des Excel-Dokuments an die USA (liegt dies daran, dass Microsoft ein US-amerikanisches Unternehmen ist :)
Ich werde versuchen, mit Kulturcodes zu experimentieren, bin mir aber noch nicht sicher, wo ich das ablegen soll. Versucht, aber das hatte keine Wirkung.
ps
Ich musste eine Zeile ändern, damit es funktioniert, indem ich eine 'Besetzung' wie unten hinzufügte
// single worksheetExcel._Worksheet workSheet =(Excel._Worksheet)excelApp.ActiveSheet;
Update: Ich habe die UK-Formatierung der Daten durch Konvertieren in das LongDateTime-Format erreicht, dies ist jedoch nur eine Problemumgehung.
Alter Thread - aber ich dachte, ich würde meinen Code hier reinwerfen. Ich habe eine kleine Funktion geschrieben, um eine Datentabelle in ein neues Excel-Blatt an einem bestimmten Pfad (Ort) zu schreiben. Außerdem müssen Sie einen Verweis auf die Microsoft Excel 14.0-Bibliothek hinzufügen.
Ich habe das benutzt, um zu extrapolieren, wie man eine Datentabelle schreibt
* Hinweis in catch-Anweisungen Ich habe eine statische Klassenreferenz für den Fehlerbehandler (Sie können diese ignorieren).
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();}}
Dies funktioniert gut, aber Sie SaveAsbeenden Ihre Excel-Prozesse danach nie mehr. Ich empfehle daher, diese hinzuzufügen und Ihre Zeile zu ersetzen , wie sie hier enthalten ist: 'XlObj.DisplayAlerts = false; WbObj.SaveAs (Ort); WbObj.Close (); XlObj.Quit (); Marshal.ReleaseComObject (WsObj); Marshal.ReleaseComObject (WbObj); Marshal.ReleaseComObject (XlObj); ' Marshal.ReleaseComObjectFügen Sie die using System.Runtime.InteropServicesBaugruppe zu Ihrem Projekt hinzu, um die Methode zu verwenden .
GrammatonCleric
0
Eine Möglichkeit wäre dies auch mit dem ACE OLEDB-Anbieter (siehe auch Verbindungszeichenfolgen für Excel ). Natürlich müsste der Anbieter installiert und registriert sein. Sie sollten es haben, wenn Sie Excel installiert haben, aber dies ist etwas, das Sie bei der Bereitstellung der App berücksichtigen müssen.
Dies ist das Beispiel für den Aufruf der Hilfsmethode von ExportHelper:ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
Der Helfer für den Export in eine Excel-Datei mit 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);}}}
Diese Lösung überträgt List<Object>Daten im Grunde genommen nach Excel. Sie verwendet DataTable, um dies zu erreichen. Ich habe eine Erweiterungsmethode implementiert, sodass im Grunde zwei Dinge erforderlich sind. 1. Eine Erweiterungsmethode.
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;}}
Dekorieren Sie Ihre DTO-Klassen mit dem Attribut [ReportHeaderAttribute("Column Name")]
Alles, was eine Spalte in Excel sein muss, muss mit dekoriert werden [ReportHeaderAttribute("Column Name")]
Dann einfach
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;
und wenn die Operation nicht für jede Tabelle DTOs erstellen möchte, gegen die sie dies ausführen wird? Wie zum Beispiel jeder meiner 1000 Tische tut dies. Das Hinzufügen des Berichtskopfattributs ist nicht im laufenden Betrieb - viel Codierung dort und das, bevor überhaupt an der eigentlichen Arbeit gearbeitet wird. Nicht an Ihre Lösung klopfen - nur darauf hinweisen, dass das Faultierprinzip hier nicht angewendet wird, da diese Lösung den Schritt des Erstellens von Dto's und des anschließenden Kompilierens hinzufügt. Ich sollte sagen - ich mag es, dass Sie die Generika verwendet haben.
Ken
0
Zum Exportieren von Daten nach Excel können Sie die ClosedXML.Report-Bibliothek ( https://github.com/ClosedXML/ClosedXML.Report ) verwenden. Glauben Sie mir, dies ist eine wundervolle Bibliothek und für sie einfach zu benutzen. Die Bibliothek benötigt kein Excel Interop. ClosedXML.Report generiert eine Excel-Datei basierend auf einer Vorlage, die Sie in Excel mit einer beliebigen Formatierung erstellen können. Beispielsweise:
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();}}
Beachten Sie, dass dies Col1NICHT in der Ausgabe enthalten ist:
Antworten:
Ich würde ClosedXML empfehlen -
Sie können eine DataTable mit einem gut lesbaren Code in ein Excel-Arbeitsblatt verwandeln :
Der Entwickler ist reaktionsschnell und hilfsbereit. Das Projekt wird aktiv entwickelt und die Dokumentation ist hervorragend.
quelle
ClosedXML.Excel.XLWorkbook
Versuchen Sie es mit einfachem Code, um DataTable in eine Excel-Datei als CSV zu konvertieren:
Dadurch wird eine neue Datei
excel.csv
in das aktuelle Arbeitsverzeichnis geschrieben, in dem sich normalerweise die EXE- Datei befindet oder von der aus Sie sie starten.quelle
"excel.csv"
Standort sein?,
(Komma ) enthält , sollte diese Zelle nach dem CSV-Standard in Anführungszeichen gesetzt werden","
und dann wie gewohnt in der Datei erscheinen. Also ja - es wird ein Problem verursachen, da dieser Code,
die Anführungszeichen nicht erkennt und anwendet.Eine elegante Option ist das Schreiben einer Erweiterungsmethode (siehe unten) für die DataTable-Klasse des .net-Frameworks.
Diese Erweiterungsmethode kann wie folgt aufgerufen werden:
Erweiterungsmethode für die DataTable-Klasse:
quelle
ExcelFilePath != null && ExcelFilePath != ""
könnte sein!String.IsNullOrEmpty(ExcelFilePath)
Die Lösung basiert auf dem Artikel von tuncalik (danke für die Idee), funktioniert aber bei großen Tischen viel schneller (und ist etwas weniger klar).
quelle
Excel.Quit(); Marshal.FinalReleaseComObject(Worksheet); Marshal.FinalReleaseComObject(HeaderRange); Marshal.FinalReleaseComObject(Excel);
Versuchen Sie diese Funktion, und übergeben Sie die Daten- und Dateipfad, in die Sie exportieren möchten
quelle
Der beste und einfachste Weg
quelle
private void releaseObject(object o) { try { while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) { } } catch { } finally { o = null; } }
Excel Interop:
Excel Interop - Effizienz und Leistung
CSV:
quelle
Klasse
Dann eine andere Methode, die den Datensatz erhält
Jetzt klicken Sie auf Ereignis
quelle
Sie können meine SwiftExcel- Bibliothek verwenden. Dies ist besonders gut, wenn Leistung und geringe Speichernutzung vorhanden sind, da Daten direkt in die Datei geschrieben werden:
Zu installierender Nuget-Befehl:
quelle
Ich wollte diese Antwort hinzufügen, weil ich viel Zeit damit verbracht habe, nach einer schnellen und zuverlässigen Methode zu suchen, und es keine vollständigen Beispiele für die Verwendung von OpenXMLWriter für diesen Zweck gab, die ich finden konnte.
Erstens ist COM / Interop (das von vielen anderen Antworten verwendet wird) für diesen Zweck in Ordnung, leidet jedoch unter einigen Empfindlichkeiten. Ich habe es jahrzehntelang verwendet und es ist größtenteils stabil, aber als ich ein Data Warehouse-Frontend für Hunderte von Benutzern implementierte, stellte ich fest, dass es je nach Computer und dem, was der Benutzer tat, zu vielen Problemen ausgesetzt war, und wechselte zu OpenXML. OpenXML DOM ist für diesen Zweck ziemlich gut, aber langsamer als die Verwendung von OpenXMLWriter. Wenn Sie in große Datenmengen (über 100 KB) mit vielen Spalten gelangen, ist DOM viel langsamer als OpenXMLWriter, daher verwende ich letzteres. Die folgende Methode schreibt 420K + Zeilen mit mehr als 30 Feldern in weniger als 30 Sekunden.
Ich hoffe, die Kommentare reichen aus, um jeden durch das zu führen, was es tut. Dies wird dadurch vereinfacht, dass alle Werte als Zeichenfolgen in die Datei geschrieben werden. Sie können jedoch eine Logik implementieren, um verschiedene Datentypen (und verschiedene Zellenformate) basierend auf dem Inhalt Ihrer Daten zu schreiben. Sie können dies auch für die Verwendung in einer DataGridView (anstelle einer DataTable) anpassen, indem Sie nur einige Dinge ändern (nämlich die Schleifen durch Spalten / Zeilen).
Ein Verweis auf DocumentFormat.OpenXML (d / l mit dem OpenXML SDK) und WindowsBase ist erforderlich.
quelle
In Bezug auf die Antwort von tuncalik , die großartig ist, besonders wenn Sie ein wenig mit dem Code spielen möchten :) aber es bringt meine Daten in Excel im amerikanischen Format, dh der 2. März 2014 in Großbritannien ist aber der 02.03.2014 in den USA sein 03/02/2014 mit Monat 1, dann Wochentag danach. Ich muss es im britischen Format haben, irgendwelche Ideen bitte?
Ich habe überprüft, ob es in meiner Datentabelle im britischen Format gespeichert ist, und auch mein Excel ist auf Großbritannien eingestellt, aber aus irgendeinem Grund denkt es beim Erstellen des Excel-Dokuments an die USA (liegt dies daran, dass Microsoft ein US-amerikanisches Unternehmen ist :)
Ich werde versuchen, mit Kulturcodes zu experimentieren, bin mir aber noch nicht sicher, wo ich das ablegen soll. Versucht, aber das hatte keine Wirkung.
ps
Ich musste eine Zeile ändern, damit es funktioniert, indem ich eine 'Besetzung' wie unten hinzufügte
Update: Ich habe die UK-Formatierung der Daten durch Konvertieren in das LongDateTime-Format erreicht, dies ist jedoch nur eine Problemumgehung.
Prost.
quelle
Sie können EasyXLS verwenden , eine Bibliothek zum Exportieren von Excel-Dateien.
Überprüfen Sie diesen Code:
Siehe auch dieses Beispiel zum Exportieren von Datentabellen in Excel in Excel .
quelle
Alter Thread - aber ich dachte, ich würde meinen Code hier reinwerfen. Ich habe eine kleine Funktion geschrieben, um eine Datentabelle in ein neues Excel-Blatt an einem bestimmten Pfad (Ort) zu schreiben. Außerdem müssen Sie einen Verweis auf die Microsoft Excel 14.0-Bibliothek hinzufügen.
Ich habe aus diesem Thread gezogen, als ich etwas in Excel geschrieben habe - Wie schreibe ich einige Daten in eine Excel-Datei (.xlsx)?
Ich habe das benutzt, um zu extrapolieren, wie man eine Datentabelle schreibt
* Hinweis in catch-Anweisungen Ich habe eine statische Klassenreferenz für den Fehlerbehandler (Sie können diese ignorieren).
quelle
SaveAs
beenden Ihre Excel-Prozesse danach nie mehr. Ich empfehle daher, diese hinzuzufügen und Ihre Zeile zu ersetzen , wie sie hier enthalten ist: 'XlObj.DisplayAlerts = false; WbObj.SaveAs (Ort); WbObj.Close (); XlObj.Quit (); Marshal.ReleaseComObject (WsObj); Marshal.ReleaseComObject (WbObj); Marshal.ReleaseComObject (XlObj); 'Marshal.ReleaseComObject
Fügen Sie dieusing System.Runtime.InteropServices
Baugruppe zu Ihrem Projekt hinzu, um die Methode zu verwenden .Eine Möglichkeit wäre dies auch mit dem ACE OLEDB-Anbieter (siehe auch Verbindungszeichenfolgen für Excel ). Natürlich müsste der Anbieter installiert und registriert sein. Sie sollten es haben, wenn Sie Excel installiert haben, aber dies ist etwas, das Sie bei der Bereitstellung der App berücksichtigen müssen.
Dies ist das Beispiel für den Aufruf der Hilfsmethode von
ExportHelper
:ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
Der Helfer für den Export in eine Excel-Datei mit ACE OLEDB:
quelle
Verwenden Sie die folgende Klasse
}}
quelle
Alles, was eine Spalte in Excel sein muss, muss mit dekoriert werden
[ReportHeaderAttribute("Column Name")]
Dann einfach
quelle
Zum Exportieren von Daten nach Excel können Sie die ClosedXML.Report-Bibliothek ( https://github.com/ClosedXML/ClosedXML.Report ) verwenden. Glauben Sie mir, dies ist eine wundervolle Bibliothek und für sie einfach zu benutzen. Die Bibliothek benötigt kein Excel Interop. ClosedXML.Report generiert eine Excel-Datei basierend auf einer Vorlage, die Sie in Excel mit einer beliebigen Formatierung erstellen können. Beispielsweise:
quelle
quelle
Reiner Beispielcode (falls er jemandem mit Ideen helfen könnte), basierend auf der Antwort von Tomasz Wiśniewski von hier: https://stackoverflow.com/a/21079709/2717521
MainWindow ExportButton:
ExportToExcel-Klasse:
quelle
Mit dem EPPlus NuGet-Paket ist das sehr einfach .
Beachten Sie, dass dies
Col1
NICHT in der Ausgabe enthalten ist:quelle