¿Cómo puedo exportar un DataTable a Excel en C #? Estoy usando Windows Forms. El DataTableestá asociado con un DataGridViewcontrol. Tengo que exportar registros DataTablea Excel.
La forma más sencilla es hacer un bucle foreach anidado en elementos y subelementos.
Saeid Yazdani
NOTA: Si está intentando pasar valores de una tabla de datos a un objeto y luego a Excel, también debería estar manejando errores de tipo de datos. Por ejemplo, los Guids eliminarán su asignación con una excepción HRESULT: 0x800A03EC. Una solución sin probar los tipos de datos es usar "ToString ()" al completar su objeto. Excel volverá a convertir los números al formato numérico por sí solo. FlashTrev abordó el problema relacionado de fecha / hora.
¿Agregar ~ 6 MB de bibliotecas referenciadas no haría que la aplicación fuera un poco pesada?
ʞᴉɯ
4
Buena pregunta @MicheleVirgilio. No he realizado ninguna prueba para cuantificar un impacto. Pero por lo que vale, no me ha molestado en ninguno de los proyectos que lo he usado, de hecho no puedo decir que lo haya notado alguna vez.
hmqcnoesy
Este código me devolvió un Excel con una sola columna con valorClosedXML.Excel.XLWorkbook
es una trampa
78
Pruebe un código simple para convertir DataTable a un archivo de Excel como csv:
Qué excelente respuesta, amigo. No tengo margen para dar más de un voto a favor a su respuesta, de lo contrario podría haber dado incluso más de 100 votos a favor.
Ashok Kumar
2
@Cuong Le - Si la celda tiene dos comas, entonces será un problema en "string.Join (", ")"
suneel ranga
@Cuong Le, ¿dónde estará la "excel.csv"ubicación?
Jogi
2
@suneelranga: si una celda (es decir, en row.ItemArray) contiene una ,(coma), según el estándar CSV, esa celda debe ir entre comillas ","y luego aparecer en el archivo como de costumbre. Entonces, sí, causará un problema porque este código no detecta ,y aplica comillas.
Tom Leys
1
@ Si8 una vez guardado, puede hacer un Process.Start (Your File) y lo abrirá para ellos. Creo que es lo más cerca que puedes conseguir ..
TimmRH
40
Una opción elegante es escribir un método de extensión (ver más abajo) para la clase DataTable de .net framework.
Este método de extensión se puede llamar de la siguiente manera:
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);
Método de extensión para la clase 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 tampoco funciona cuando intenté usarlo en un servidor. Buen punto para mencionar.
Si8
Esto funcionará pero es lento. Es mejor copiar al portapapeles y pegar en Excel. Si trabaja en más de 1000 registros, esto llevará un tiempo.
Alex M
25
Solución basada en el artículo tuncalik (gracias por la idea), pero en el caso de tablas grandes está funcionando mucho más rápido (y es un poco menos claro).
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);}}}
La respuesta de tuncalik me tomó casi un minuto, esto es en 1 segundo si toma mucho tiempo ... De hecho, me sorprendió.
Wilsu
2
Esta es la muestra más rápida que he probado, gran trabajo. Tuve que usar Marshal para liberar el archivo después. Excel.Quit(); Marshal.FinalReleaseComObject(Worksheet); Marshal.FinalReleaseComObject(HeaderRange); Marshal.FinalReleaseComObject(Excel);
Dave Kelly
¿Es necesario instalar Office?
Parshuram Kalvikatte
De lo contrario, funciona perfectamente, pero el color de fondo de mi encabezado se establece en Negro siempre al usar esta solución en la aplicación de consola. ¿¿Cuál podría ser la razón??
Zaveed Abbasi
15
Pruebe esta función, pase la tabla de datos y la ruta del archivo donde desea exportar
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;}}
Tenga en cuenta que esto realmente no usará las celdas de la tabla en el documento de Excel, sino que todo para cada fila se imprimirá en la primera celda de cada fila.
Banshee
@Banshee No, Excel comprende completamente los archivos CSV.
NickG
Tampoco funciona con mi Excel. Los datos de cada fila están en la primera celda.
Mitulát báti
5
La mejor y más sencilla forma
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);}}
(por favor, esté aquí) si hay más de un archivo de Excel abierto, ¿esta función de lanzamiento los destruye a todos o solo al que se pasó como parámetro?
Elliott Addi
1
Interoperabilidad de Excel:
Este método evita que las fechas pasen de dd-mm-aaaa a mm-dd-aaaa
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;}
Si no le importa que se cambien las fechas, utilice el enlace ver que muestra cómo completar todas las celdas en la hoja de cálculo de Excel en una línea de código:
Simplemente haga uso de la biblioteca CloseMXL.Excel . Es fácil y bastante rápido también.
Clase
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;}}}}
Luego, otro método que obtiene el conjunto de datos.
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;}
Ahora haz clic en el botón Evento
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();}}}
Puede usar mi biblioteca SwiftExcel . Es especialmente bueno cuando el rendimiento y el bajo uso de memoria se implementan, ya que escribe datos directamente en el archivo:
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);}}}
Quería agregar esta respuesta porque pasé mucho tiempo buscando un método rápido y confiable para hacer esto y no existían ejemplos completos de uso de OpenXMLWriter para este propósito en ningún lugar que pudiera encontrar.
Primero, COM / Interop (que usan muchas de las otras respuestas) está bien para este propósito, pero adolece de algunas sensibilidades. Lo he usado durante décadas y es mayormente estable, pero al implementar un front-end de almacén de datos para cientos de usuarios, encontré que estaba sujeto a demasiados problemas según la máquina y lo que hizo el usuario, así que cambié a OpenXML. OpenXML DOM es bastante bueno para este propósito, pero es más lento que usar OpenXMLWriter. Cuando ingresa a grandes conjuntos de datos (100K +) con muchas columnas, DOM es mucho más lento que OpenXMLWriter, por lo que uso este último. El siguiente método escribe 420K + filas con más de 30 campos en menos de 30 segundos.
Espero que los comentarios sean suficientes para guiar a cualquiera a través de lo que está haciendo. Está simplificado, ya que escribe todos los valores en el archivo como cadenas, pero puede implementar la lógica para escribir varios tipos de datos (y usar varios formatos de celda) según el contenido de sus datos. También puede adaptar esto para su uso en un DataGridView (en lugar de un DataTable) cambiando solo algunas cosas (es decir, los bucles a través de columnas / filas).
Se requiere una referencia a DocumentFormat.OpenXML (d / l con OpenXML SDK) y 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
Muchas gracias por dedicar tiempo a esta respuesta. Tengo un cliente que tiene una solución que funciona en Excel Interop, pero se queja de lo lento que es. Vi algunas otras respuestas a preguntas que me guiaron hacia OpenXML, pero me alegra tener un atajo para comenzar.
Brandon Barkley
1
No hay problema. Sigo usando COM, pero solo en entornos sobre los que tengo un control total. He estado usando este enfoque OpenXML en una aplicación con un par de cientos de usuarios durante un par de meses y no he tenido ningún problema en comparación con los errores semanales con COM. También busqué soluciones de terceros, como las que se mencionan aquí, pero prefiero escribirlo yo mismo para poder hacerlo lo más eficiente posible.
WATYF
0
En lo que respecta a la respuesta de tuncalik , que es genial, especialmente si quieres jugar un poco con el código :) pero está poniendo mis fechas en Excel en formato americano, es decir, el 2 de marzo de 2014 en el Reino Unido es el 02/03/2014 pero en los EE. UU. el 02/03/2014 con el mes 1, luego el día de la semana siguiente. Necesito tenerlo en formato del Reino Unido, ¿alguna idea, por favor?
He comprobado que está almacenado en formato del Reino Unido en mi DataTable y también mi Excel está configurado en el Reino Unido, pero por alguna razón, cuando crea el documento de Excel, piensa que es EE. UU. (¿Es esto porque Microsoft es una empresa de EE. UU. :)
Intentaré experimentar con códigos culturales, pero todavía no estoy seguro de dónde poner eso. Intenté pero esto no tuvo ningún efecto.
PD
Tuve que cambiar una línea para que funcionara agregando un 'elenco' como se muestra a continuación
// single worksheetExcel._Worksheet workSheet =(Excel._Worksheet)excelApp.ActiveSheet;
Actualización: he logrado el formateo de las fechas en el Reino Unido al convertirlas al formato LongDateTime, aunque es solo una solución.
Hilo antiguo, pero pensé que lanzaría mi código aquí. Escribí una pequeña función para escribir una tabla de datos en una nueva hoja de Excel en una ruta específica (ubicación). También deberá agregar una referencia a la biblioteca de Microsoft Excel 14.0.
Lo usé para extrapolar cómo escribir una tabla de datos
* tenga en cuenta que en las declaraciones de captura tengo una referencia de clase estática de errorhandler (puede ignorarlos)
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();}}
Esto funciona bien, sin embargo, nunca matas tus procesos de Excel después, así que sugiero agregar esto, reemplazando tu SaveAslínea como está incluida aquí: 'XlObj.DisplayAlerts = false; WbObj.SaveAs (ubicación); WbObj.Close (); XlObj.Quit (); Marshal.ReleaseComObject (WsObj); Marshal.ReleaseComObject (WbObj); Marshal.ReleaseComObject (XlObj); ' Para usar el Marshal.ReleaseComObjectmétodo, agregue el using System.Runtime.InteropServicesensamblaje a su proyecto.
GrammatonCleric
0
Una forma de hacerlo sería también con ACE OLEDB Provider (consulte también las cadenas de conexión para Excel ). Por supuesto, tendría que tener el proveedor instalado y registrado. Debería tenerlo, si tiene Excel instalado, pero esto es algo que debe tener en cuenta al implementar la aplicación.
Este es el ejemplo de cómo llamar al método auxiliar desde ExportHelper:ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
El ayudante para exportar a un archivo de Excel usando 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);}}}
Esta solución básicamente está enviando List<Object>datos a Excel, utiliza DataTable para lograr esto, implementé un método de extensión, por lo que básicamente se necesitan dos cosas. 1. Un método de extensión.
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;}}
Decora tus clases DTO con el atributo [ReportHeaderAttribute("Column Name")]
Todo lo que necesita ser una columna en Excel debe estar decorado con [ReportHeaderAttribute("Column Name")]
Entonces simplemente
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;
y si el operador no quiere crear DTO para cada mesa contra la que van a ejecutar esto? Como, por ejemplo, cada una de mis mil mesas hace esto. Agregar el atributo de encabezado del informe no es sobre la marcha: hay mucha codificación allí y eso incluso antes de trabajar en el trabajo real. No estropear su solución, solo señalar que el principio de pereza no se utiliza aquí, ya que esta solución agrega el paso de crear dto's y luego compilar ... Debo decir: me gusta que haya utilizado los genéricos.
Ken
0
Para exportar datos a Excel, puede utilizar la biblioteca ClosedXML.Report ( https://github.com/ClosedXML/ClosedXML.Report ). Créame, esta es una biblioteca maravillosa y fácil de usar para ella. La biblioteca no necesita Excel Interop. ClosedXML.Report genera un archivo de Excel basado en una plantilla que puede crear en Excel usando cualquier formato. Por ejemplo:
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
Código puramente de muestra (en caso de que pueda ayudar a alguien con algunas ideas), basado en la respuesta de Tomasz Wiśniewski desde aquí:
https://stackoverflow.com/a/21079709/2717521
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();}}
Respuestas:
Recomendaría ClosedXML -
Puede convertir un DataTable en una hoja de cálculo de Excel con un código muy legible:
El desarrollador es receptivo y útil. El proyecto se desarrolla activamente y la documentación es excelente.
fuente
ClosedXML.Excel.XLWorkbook
Pruebe un código simple para convertir DataTable a un archivo de Excel como csv:
Esto escribirá un nuevo archivo
excel.csv
en el directorio de trabajo actual que generalmente es donde está el .exe o desde donde lo inicia.fuente
"excel.csv"
ubicación?,
(coma), según el estándar CSV, esa celda debe ir entre comillas","
y luego aparecer en el archivo como de costumbre. Entonces, sí, causará un problema porque este código no detecta,
y aplica comillas.Una opción elegante es escribir un método de extensión (ver más abajo) para la clase DataTable de .net framework.
Este método de extensión se puede llamar de la siguiente manera:
Método de extensión para la clase DataTable:
fuente
ExcelFilePath != null && ExcelFilePath != ""
podría ser!String.IsNullOrEmpty(ExcelFilePath)
Solución basada en el artículo tuncalik (gracias por la idea), pero en el caso de tablas grandes está funcionando mucho más rápido (y es un poco menos claro).
fuente
Excel.Quit(); Marshal.FinalReleaseComObject(Worksheet); Marshal.FinalReleaseComObject(HeaderRange); Marshal.FinalReleaseComObject(Excel);
Pruebe esta función, pase la tabla de datos y la ruta del archivo donde desea exportar
fuente
La mejor y más sencilla forma
fuente
private void releaseObject(object o) { try { while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) { } } catch { } finally { o = null; } }
Interoperabilidad de Excel:
Interoperabilidad de Excel: eficiencia y rendimiento
CSV:
fuente
Clase
Luego, otro método que obtiene el conjunto de datos.
Ahora haz clic en el botón Evento
fuente
Puede usar mi biblioteca SwiftExcel . Es especialmente bueno cuando el rendimiento y el bajo uso de memoria se implementan, ya que escribe datos directamente en el archivo:
Comando Nuget para instalar:
fuente
Quería agregar esta respuesta porque pasé mucho tiempo buscando un método rápido y confiable para hacer esto y no existían ejemplos completos de uso de OpenXMLWriter para este propósito en ningún lugar que pudiera encontrar.
Primero, COM / Interop (que usan muchas de las otras respuestas) está bien para este propósito, pero adolece de algunas sensibilidades. Lo he usado durante décadas y es mayormente estable, pero al implementar un front-end de almacén de datos para cientos de usuarios, encontré que estaba sujeto a demasiados problemas según la máquina y lo que hizo el usuario, así que cambié a OpenXML. OpenXML DOM es bastante bueno para este propósito, pero es más lento que usar OpenXMLWriter. Cuando ingresa a grandes conjuntos de datos (100K +) con muchas columnas, DOM es mucho más lento que OpenXMLWriter, por lo que uso este último. El siguiente método escribe 420K + filas con más de 30 campos en menos de 30 segundos.
Espero que los comentarios sean suficientes para guiar a cualquiera a través de lo que está haciendo. Está simplificado, ya que escribe todos los valores en el archivo como cadenas, pero puede implementar la lógica para escribir varios tipos de datos (y usar varios formatos de celda) según el contenido de sus datos. También puede adaptar esto para su uso en un DataGridView (en lugar de un DataTable) cambiando solo algunas cosas (es decir, los bucles a través de columnas / filas).
Se requiere una referencia a DocumentFormat.OpenXML (d / l con OpenXML SDK) y WindowsBase.
fuente
En lo que respecta a la respuesta de tuncalik , que es genial, especialmente si quieres jugar un poco con el código :) pero está poniendo mis fechas en Excel en formato americano, es decir, el 2 de marzo de 2014 en el Reino Unido es el 02/03/2014 pero en los EE. UU. el 02/03/2014 con el mes 1, luego el día de la semana siguiente. Necesito tenerlo en formato del Reino Unido, ¿alguna idea, por favor?
He comprobado que está almacenado en formato del Reino Unido en mi DataTable y también mi Excel está configurado en el Reino Unido, pero por alguna razón, cuando crea el documento de Excel, piensa que es EE. UU. (¿Es esto porque Microsoft es una empresa de EE. UU. :)
Intentaré experimentar con códigos culturales, pero todavía no estoy seguro de dónde poner eso. Intenté pero esto no tuvo ningún efecto.
PD
Tuve que cambiar una línea para que funcionara agregando un 'elenco' como se muestra a continuación
Actualización: he logrado el formateo de las fechas en el Reino Unido al convertirlas al formato LongDateTime, aunque es solo una solución.
salud.
fuente
Puede utilizar EasyXLS que es una biblioteca para exportar archivos de Excel.
Verifique este código:
Consulte también este ejemplo sobre cómo exportar tablas de datos para sobresalir en C # .
fuente
Hilo antiguo, pero pensé que lanzaría mi código aquí. Escribí una pequeña función para escribir una tabla de datos en una nueva hoja de Excel en una ruta específica (ubicación). También deberá agregar una referencia a la biblioteca de Microsoft Excel 14.0.
Saqué de este hilo al escribir cualquier cosa para sobresalir: cómo escribir algunos datos en un archivo de Excel (.xlsx)
Lo usé para extrapolar cómo escribir una tabla de datos
* tenga en cuenta que en las declaraciones de captura tengo una referencia de clase estática de errorhandler (puede ignorarlos)
fuente
SaveAs
línea como está incluida aquí: 'XlObj.DisplayAlerts = false; WbObj.SaveAs (ubicación); WbObj.Close (); XlObj.Quit (); Marshal.ReleaseComObject (WsObj); Marshal.ReleaseComObject (WbObj); Marshal.ReleaseComObject (XlObj); ' Para usar elMarshal.ReleaseComObject
método, agregue elusing System.Runtime.InteropServices
ensamblaje a su proyecto.Una forma de hacerlo sería también con ACE OLEDB Provider (consulte también las cadenas de conexión para Excel ). Por supuesto, tendría que tener el proveedor instalado y registrado. Debería tenerlo, si tiene Excel instalado, pero esto es algo que debe tener en cuenta al implementar la aplicación.
Este es el ejemplo de cómo llamar al método auxiliar desde
ExportHelper
:ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
El ayudante para exportar a un archivo de Excel usando ACE OLEDB:
fuente
usa la siguiente clase
}
fuente
Todo lo que necesita ser una columna en Excel debe estar decorado con
[ReportHeaderAttribute("Column Name")]
Entonces simplemente
fuente
Para exportar datos a Excel, puede utilizar la biblioteca ClosedXML.Report ( https://github.com/ClosedXML/ClosedXML.Report ). Créame, esta es una biblioteca maravillosa y fácil de usar para ella. La biblioteca no necesita Excel Interop. ClosedXML.Report genera un archivo de Excel basado en una plantilla que puede crear en Excel usando cualquier formato. Por ejemplo:
fuente
fuente
Código puramente de muestra (en caso de que pueda ayudar a alguien con algunas ideas), basado en la respuesta de Tomasz Wiśniewski desde aquí: https://stackoverflow.com/a/21079709/2717521
Botón de exportación de la ventana principal:
Clase ExportToExcel:
fuente
Con el paquete EPPlus NuGet, es muy fácil .
Tenga en cuenta que
Col1
NO está en la salida:fuente