How to export DataTable to Excel

后端 未结 21 2323
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 15:36

How can I export a DataTable to Excel in C#? I am using Windows Forms. The DataTable is associated with a DataGridView control. I have

相关标签:
21条回答
  • 2020-11-22 15:37

    Old thread - but thought i would throw my code in here. I wrote a little function to write a data table to a new excel sheet at a specified path (location). Also you will need to add a reference to microsoft excel 14.0 library.

    I pulled from this thread on writing anything to excel - How to write some data to excel file(.xlsx)

    i used that to extrapolate how to write a datatable

    *note in catch statements i have an errorhandler static class reference (you can ignore those)

     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 
    
     private void WriteToExcel(System.Data.DataTable dt, string location)
        {
            //instantiate excel objects (application, workbook, worksheets)
            excel.Application XlObj = new excel.Application();
            XlObj.Visible = false;
            excel._Workbook WbObj = (excel.Workbook)(XlObj.Workbooks.Add(""));
            excel._Worksheet WsObj = (excel.Worksheet)WbObj.ActiveSheet;
    
            //run through datatable and assign cells to values of datatable
            try
            {
                int row = 1; int col = 1;
                foreach (DataColumn column in dt.Columns)
                {
                    //adding columns
                    WsObj.Cells[row, col] = column.ColumnName;
                    col++;
                }
                //reset column and row variables
                col = 1;
                row++;
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    //adding data
                    foreach (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();                
            }
        }
    
    0 讨论(0)
  • 2020-11-22 15:37

    To export data to Excel, you can use the ClosedXML.Report library (https://github.com/ClosedXML/ClosedXML.Report). Believe me, this is a wonderful library and easy for her to use. The library does not need Excel Interop. ClosedXML.Report generates an Excel file based on a template that you can create in Excel using any formatting. For example:

        var template = new XLTemplate(@".\Templates\report.xlsx");
    
        using (var db = new DbDemos())
        {
            var cust = db.customers.LoadWith(c => c.Orders).First();
            template.AddVariable(cust);
            template.Generate();
        }
    
        template.SaveAs(outputFile);
    
    0 讨论(0)
  • 2020-11-22 15:38

    Just Make use of the CloseMXL.Excel Library. It's easy and pretty fast too.

    Class

    private DataTable getAllList()
            {
                string constr = ConfigurationManager.ConnectionStrings["RConnection"].ConnectionString;
                using (SqlConnection con = new SqlConnection(constr))
                {
                    using (SqlCommand cmd = new SqlCommand("SELECT EmpId, gender, EmpName, pOnHold FROM Employee  WHERE EmpId= '"+ AnyVariable + "' ORDER BY EmpName"))
                    {
                        using (SqlDataAdapter da = new SqlDataAdapter())
                        {
                            DataTable dt = new DataTable();
                            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;
                        }
                    }
                }
            }
    

    Then another method which get the Dataset

    public DataSet getDataSetExportToExcel()
            {
                DataSet ds = new DataSet();
                DataTable dtEmp = new DataTable("CLOT List");
                dtEmp = getAllList();
                 ds.Tables.Add(dtEmp);
                 ds.Tables[0].TableName = "Employee"; //If you which to use Mutliple Tabs
                 return ds;
              }
    

    Now you Button Click Event

    protected void btn_Export_Click(object sender, EventArgs e)
            {
                DataSet ds = getDataSetExportToExcel();
    
                using (XLWorkbook wb = new XLWorkbook())
                {
                    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 (MemoryStream MyMemoryStream = new MemoryStream())
                    {
                        wb.SaveAs(MyMemoryStream);
                        MyMemoryStream.WriteTo(Response.OutputStream);
    
                        Response.Flush();
                        Response.End();
                    }
                }
            }
    
    0 讨论(0)
  • 2020-11-22 15:40

    I would recommend ClosedXML -

    You can turn a DataTable into an Excel worksheet with some very readable code:

    XLWorkbook wb = new XLWorkbook();
    DataTable dt = GetDataTableOrWhatever();
    wb.Worksheets.Add(dt,"WorksheetName");
    

    The developer is responsive and helpful. The project is actively developed, and the documentation is superb.

    0 讨论(0)
  • 2020-11-22 15:40

    Solution based on tuncalik (thanks for idea) article, but in case of big tables is working much more faster (and is a little less clear).

    public static class My_DataTable_Extensions
    {
        /// <summary>
        /// Export DataTable to Excel file
        /// </summary>
        /// <param name="DataTable">Source DataTable</param>
        /// <param name="ExcelFilePath">Path to result file name</param>
        public static void ExportToExcel(this System.Data.DataTable DataTable, string ExcelFilePath = null)
        {
            try
            {
                int ColumnsCount;
    
                if (DataTable == null || (ColumnsCount = DataTable.Columns.Count) == 0)
                    throw new Exception("ExportToExcel: Null or empty input table!\n");
    
                // load excel, and create a new workbook
                Microsoft.Office.Interop.Excel.Application Excel = new Microsoft.Office.Interop.Excel.Application();
                Excel.Workbooks.Add();
    
                // single worksheet
                Microsoft.Office.Interop.Excel._Worksheet Worksheet = Excel.ActiveSheet;
    
                object[] Header = new object[ColumnsCount];
    
                // column headings               
                for (int i = 0; i < ColumnsCount; i++)
                    Header[i] = DataTable.Columns[i].ColumnName;
    
                Microsoft.Office.Interop.Excel.Range HeaderRange = 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;
    
                // DataCells
                int RowsCount = DataTable.Rows.Count;
                object[,] Cells = new object[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 fielpath
                if (ExcelFilePath != null && ExcelFilePath != "")
                {
                    try
                    {
                        Worksheet.SaveAs(ExcelFilePath);
                        Excel.Quit();
                        System.Windows.MessageBox.Show("Excel file saved!");
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
                            + ex.Message);
                    }
                }
                else    // no filepath is given
                {
                    Excel.Visible = true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("ExportToExcel: \n" + ex.Message);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 15:41

    I wanted to add this answer because I spent a great deal of time looking for a fast, reliable method to do this and no complete examples of using OpenXMLWriter for this purpose existed anywhere that I could find.

    First, COM/Interop (which many of the other answers use) is OK for this purpose, but it suffers from some sensitivities. I've used it for decades and it's mostly stable, but when implementing a data warehouse front-end for hundreds of users, I found it to be subject to too many issues depending on the machine and what the user did, so I switched to OpenXML. OpenXML DOM is fairly good for this purpose, but it's slower than using OpenXMLWriter. When you get into large datasets (100K+) with lots of columns, DOM is much slower than OpenXMLWriter, so I use the latter. The method below writes 420K+ rows with 30+ fields in less than 30 seconds.

    I hope the comments are sufficient to guide anyone through what it's doing. It is simplified, in that it writes all values to the file as strings, but you can implement logic to write various datatypes (and use various cell formats) based on the content of your data. You can also adapt this for use on a DataGridView (instead of a DataTable) by changing just a few things (namely the loops through columns/rows).

    A reference to DocumentFormat.OpenXML (d/l with the OpenXML SDK) and WindowsBase is required.

    Imports DocumentFormat.OpenXml
    Imports DocumentFormat.OpenXml.Spreadsheet
    Imports DocumentFormat.OpenXml.Packaging
    
    Public Sub ExportToExcelXML(ByRef dt As DataTable, filename As String)
        Dim wbp As WorkbookPart, wsp As WorksheetPart
        'If this DataTable has more rows in it than can fit in Excel, throw an exception
        If dt.Rows.Count > 1048575 Then Throw New Exception("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 OpenXML SpreadsheetDocument...
        Using xls = SpreadsheetDocument.Create(filename, SpreadsheetDocumentType.Workbook)
            'Add a WorkbookPart to the Spreadsheet Doc, then add a WorksheetPart to the WorkbookPart.
            wbp = xls.AddWorkbookPart()
            wsp = wbp.AddNewPart(Of WorksheetPart)
            '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 As WorkbookStylesPart = wbp.AddNewPart(Of WorkbookStylesPart)
            Dim ss As New Stylesheet
            'Create the only two Fonts we're going to use (Regular and Bold).
            Dim fBold As New Font
            fBold.Append(New Bold)
            Dim fnts As New Fonts
            fnts.Append(New Font) 'This creates the default (unmodified, regular) Font. It's added first, so its index is 0.
            fnts.Append(fBold) 'This creates the Bold font. It's added second, so its index is 1.
            'Create the default Fill/Border settings (these have to be here, even though I don't set any custom fills/borders).
            Dim flls As New Fills
            Dim brdrs As New Borders
            flls.Append(New Fill)
            brdrs.Append(New Border)
            'Now I have to add formats (NumberFormat and CellFormat). First, you create a NumberFormat. This is basically the pattern of 
            '   the format (i.e. "@" for Text). 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 163 is where the built-in Excel formats end.
            Dim nbrfmts As New NumberingFormats
            nbrfmts.Append(New NumberingFormat With {.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 As New CellFormats()
            cellfmts.Append(New CellFormat() With {.FontId = 0, .NumberFormatId = 164, .FillId = 0, .BorderId = 0})
            cellfmts.Append(New CellFormat() With {.FontId = 1, .NumberFormatId = 164,
                .Alignment = New Alignment() 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 As OpenXmlWriter = OpenXmlWriter.Create(wsp)
                'Write the start element for the Worksheet and the Columns...
                oxw.WriteStartElement(New Worksheet)
                oxw.WriteStartElement(New Columns())
                'Now I'm going to loop through the columns in the DataTable...
                For c As Integer = 0 To dt.Columns.Count - 1
                    'Now we'll get the width for the column. To do this, we loop through all of the rows and measure the width of the text 
                    '   using the default Excel Font (currently Font: Calibri Size: 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 = New System.Drawing.Font("Calibri", 11)
                    Dim wid As Double = 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 as Excel would make it.
                    Dim tmp As Double = g.MeasureString(dt.Columns(c).ColumnName, New System.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.
                    For Each row As DataRow In dt.Rows
                        If tmp > wid Then wid = tmp
                        tmp = g.MeasureString(row(c).ToString, fnt).Width
                    Next
                    '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 As New List(Of OpenXmlAttribute) From {New OpenXmlAttribute("min", Nothing, c + 1), New OpenXmlAttribute("max", Nothing, c + 1),
                        New OpenXmlAttribute("width", Nothing, System.Math.Round((wid - 12 + 5) / 7D + 1, 2))}
                    oxw.WriteStartElement(New Column(), oxa)
                    oxw.WriteEndElement()
                Next
                'CLose out the Columns collection.
                oxw.WriteEndElement()
                'Write the start element for the SheetData...
                oxw.WriteStartElement(New SheetData)
                'Write the start element for the Header row.
                oxw.WriteStartElement(New Row)
                'Loop through the Columns in the dt.
                For Each col As DataColumn In dt.Columns
                    'Write a cell for this column's Header. All Header cells are written with a DataType of String ("str"). 
                    '   I ALSO apply the "Header" CellFormat (StyleIndex 1) to all of the Header Cells. This makes them Bold and Centered.
                    WriteCell(oxw, col.ColumnName, "str", 1)
                Next
                'Close out the Header row.
                oxw.WriteEndElement()
                'Loop through all of the rows in the dt...
                For Each row As DataRow In dt.Rows
                    'Write a StartElement for this row...
                    oxw.WriteStartElement(New Row)
                    'Loop through all of the columns in the dt...
                    For c As Integer = 0 To dt.Columns.Count - 1
                        'Write a value in this row/column to the Excel file. I use the datatype of "String" and the default CellFormat/StyleIndex.
                        WriteCell(oxw, row(c).ToString, "str", 0)
                    Next
                    'Close out this row.
                    oxw.WriteEndElement()
                Next
                'Close out the Worksheet and SheetData elements...
                oxw.WriteEndElement()
                oxw.WriteEndElement()
            End Using
            'Now we're going to create an OpenXMLWriter using the WorkbookPart (that we created above)...
            Using oxw As OpenXmlWriter = OpenXmlWriter.Create(wbp)
                'Add starting elements for the Workbook and Sheets collection.
                oxw.WriteStartElement(New Workbook())
                oxw.WriteStartElement(New Sheets())
                'Add the Sheet (name the Sheet after the file name minus the extension).
                oxw.WriteElement(New Sheet() With {.Name = Path.GetFileNameWithoutExtension(filename), .SheetId = 1, .Id = xls.WorkbookPart.GetIdOfPart(wsp)})
                'Write End elements for the Workbook/Sheets
                oxw.WriteEndElement()
                oxw.WriteEndElement()
            End Using
        End Using
    
    End Sub
    
    'This Sub is used to write a value to a Cell using OpenXMLWriter.
    Private Sub WriteCell(ByRef oxw As OpenXmlWriter, value As String, datatype As String, style As UInt32Value)
        Dim oxa As New List(Of OpenXmlAttribute) From {New OpenXmlAttribute("t", Nothing, datatype), New OpenXmlAttribute("s", Nothing, style)}
        oxw.WriteStartElement(New Cell(), oxa)
        If value <> Nothing Then oxw.WriteElement(New CellValue(value))
        oxw.WriteEndElement()
    End Sub
    
    0 讨论(0)
提交回复
热议问题