How to export DataTable to Excel

后端 未结 21 2326
爱一瞬间的悲伤
爱一瞬间的悲伤 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 16:02

    Excel Interop:

    This method prevents Dates getting flipped from dd-mm-yyyy to mm-dd-yyyy

    public bool DataTableToExcelFile(DataTable dt, string targetFile)
    {
        const bool dontSave = false;
        bool success = true;
    
        //Exit if there is no rows to export
        if (dt.Rows.Count == 0) return false;
    
        object misValue = System.Reflection.Missing.Value;
        List<int> dateColIndex = new List<int>();
        Excel.Application excelApp = new Excel.Application();
        Excel.Workbook excelWorkBook = excelApp.Workbooks.Add(misValue);
        Excel.Worksheet excelWorkSheet = excelWorkBook.Sheets("sheet1");
    
        //Iterate through the DataTable and populate the Excel work sheet
        try {
            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 columns
                        if (dt.Columns(j).DataType is typeof(DateTime)) {
                            excelWorkSheet.Cells(1, j + 1).EntireColumn.NumberFormat = "d-MMM-yyyy;@";
                            dateColIndex.Add(j);
                        } 
                        //else if ... Feel free to add more Formats
    
                        else {
                            //Otherwise Format the column as text
                            excelWorkSheet.Cells(1, j + 1).EntireColumn.NumberFormat = "@";
                        }
                        excelWorkSheet.Cells(1, j + 1) = dt.Columns(j).Caption;
                    } 
                    else if (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;
    }
    

    If you dont care about Dates being flipped, then use see link that shows how to populate all the cells in the Excel spreadsheet in one line of code:

    Excel Interop - Efficiency and performance

    CSV:

    public string DataTableToCSV(DataTable dt, bool includeHeader, string rowFilter, string sortFilter, bool useCommaDelimiter = false, bool truncateTimesFromDates = false)
    {
        dt.DefaultView.RowFilter = rowFilter;
        dt.DefaultView.Sort = sortFilter;
        DataView dv = dt.DefaultView;
        string csv = DataTableToCSV(dv.ToTable, includeHeader, useCommaDelimiter, truncateTimesFromDates);
        //reset the Filtering
        dt.DefaultView.RowFilter = string.Empty;
        return csv;
    }
    
    public string DataTableToCsv(DataTable dt, bool includeHeader, bool useCommaDelimiter = false, bool truncateTimesFromDates = false)
    {
        StringBuilder sb = new StringBuilder();
        string delimter = Constants.vbTab;
        if (useCommaDelimiter)
            delimter = ",";
    
        if (includeHeader) {
            foreach (DataColumn dc in dt.Columns) {
                sb.AppendFormat("{0}" + Constants.vbTab, dc.ColumnName);
            }
    
            //remove the last Tab
            sb.Remove(sb.ToString.Length - 1, 1);
            sb.Append(Environment.NewLine);
        }
    
        foreach (DataRow dr in dt.Rows) {
            foreach (DataColumn dc in dt.Columns) {
                if (Information.IsDate(dr(dc.ColumnName).ToString()) & dr(dc.ColumnName).ToString().Contains(".") == false & truncateTimesFromDates) {
                    sb.AppendFormat("{0}" + delimter, Convert.ToDateTime(dr(dc.ColumnName).ToString()).Date.ToShortDateString());
                } else {
                    sb.AppendFormat("{0}" + delimter, CheckDBNull(dr(dc.ColumnName).ToString().Replace(",", "")));
                }
            }
            //remove the last Tab
            sb.Remove(sb.ToString.Length - 1, 1);
            sb.Append(Environment.NewLine);
        }
        return sb.ToString;
    }
    
    public enum enumObjectType
    {
        StrType = 0,
        IntType = 1,
        DblType = 2
    }
    
    public object CheckDBNull(object obj, enumObjectType ObjectType = enumObjectType.StrType)
    {
        object objReturn = null;
        objReturn = obj;
        if (ObjectType == enumObjectType.StrType & Information.IsDBNull(obj)) {
            objReturn = "";
        } else if (ObjectType == enumObjectType.IntType & Information.IsDBNull(obj)) {
            objReturn = 0;
        } else if (ObjectType == enumObjectType.DblType & Information.IsDBNull(obj)) {
            objReturn = 0.0;
        }
        return objReturn;
    }
    
    0 讨论(0)
  • 2020-11-22 16:02

    With the EPPlus NuGet package, it's very easy.

    public class TestObject
    {
        public int Col1 { get; set; }
        public int Col2 { get; set; }
        public string Col3 { get; set; }
        public DateTime Col4 { get; set; }
    }
    
    [TestMethod]
    public void LoadFromCollection_MemberList_Test()
    {
        //https://stackoverflow.com/questions/32587834/epplus-loadfromcollection-text-converted-to-number/32590626#32590626
    
        var TestObjectList = new List<TestObject>();
        for (var i = 0; i < 10; i++)
            TestObjectList.Add(new TestObject {Col1 = i, Col2 = i*10, Col3 = (i*10) + "E4"});
    
        //Create a test file
        var fi = new FileInfo(@"c:\temp\LoadFromCollection_MemberList_Test.xlsx");
        if (fi.Exists)
            fi.Delete();
    
        using (var pck = new ExcelPackage(fi))
        {
            //Do NOT include Col1
            var 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();
        }
    }
    

    Notice that Col1 is NOT in the output:

    0 讨论(0)
  • 2020-11-22 16:03

    You can use my SwiftExcel library. It is especially good when performance and low memory usage come in place as it writes data directly to the file:

    using (var ew = new ExcelWriter("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);
            }
        }
    }
    

    Nuget command to install:

    Install-Package SwiftExcel
    
    0 讨论(0)
提交回复
热议问题