Как экспортировать DataTable в Excel - PullRequest
93 голосов
/ 21 ноября 2011

Как я могу экспортировать DataTable в Excel в C #? Я использую Windows Forms. DataTable связан с элементом управления DataGridView. Я должен экспортировать записи DataTable в Excel.

Ответы [ 16 ]

0 голосов
/ 31 января 2018

Это решение в основном отправляет List<Object> данные в Excel, для этого используется DataTable, я реализовал метод расширения, поэтому в основном есть две вещи необходимо. 1. Метод расширения.

public static class ReportHelper
{
    public static string ToExcel<T>(this IList<T> data)
    {
        PropertyDescriptorCollection properties =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        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 # 1471
        DataRow 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;
    }

    private static string GetColumnHeader(PropertyDescriptor prop)
    {
        return ((FGMS.Entity.Extensions.ReportHeaderAttribute)(prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)])).ReportHeaderText;
    }       
}
  1. Украсьте свои классы DTO Атрибутом [ReportHeaderAttribute("Column Name")]
public class UserDTO
    {
        public int Id { get; set; }
        public int SourceId { get; set; }
        public string SourceName { get; set; }

        [ReportHeaderAttribute("User Type")]
        public string UsereType { get; set; }

        [ReportHeaderAttribute("Address")]
        public string Address{ get; set; }

        [ReportHeaderAttribute("Age")]
        public int Age{ get; set; }

        public bool IsActive { get; set; }

        [ReportHeaderAttribute("Active")]
        public string IsActiveString
        {
            get
            {
                return IsActive ? "Yes" : "No";
            }
        }}

Все, что должно быть столбцом в Excel, должно быть украшено [ReportHeaderAttribute("Column Name")]

Тогда просто

Var userList = Service.GetUsers() //Returns List of UserDTO;
var excelFilePath = userList.ToExcel();

HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
            var stream = new FileStream(excelFilePath, FileMode.Open);
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentType =
                new MediaTypeHeaderValue("application/vnd.ms-excel");
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "UserList.xls" };

            return result;
0 голосов
/ 03 июля 2017

используйте следующий класс

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
{
public class ExcelProcesser
{
    public void WriteToExcel(System.Data.DataTable dt)
    {
        excel.Application XlObj = new excel.Application();
        XlObj.Visible = false;
        excel._Workbook WbObj = (excel.Workbook)(XlObj.Workbooks.Add(""));
        excel._Worksheet WsObj = (excel.Worksheet)WbObj.ActiveSheet;
        object misValue = System.Reflection.Missing.Value;


        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(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);
        }
    }
}

}

0 голосов
/ 01 мая 2016

Один из способов сделать это будет также с ACE OLEDB Provider (см. Также строки подключения для Excel ).Конечно, вам нужно будет установить и зарегистрировать провайдера.Он должен быть у вас, если у вас установлен Excel, но вы должны учитывать это при развертывании приложения.

Это пример вызова вспомогательного метода из ExportHelper: ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");

Помощник для экспорта в файл Excel с использованием ACE OLEDB:

public class ExportHelper
{
    private const string ExcelOleDbConnectionStringTemplate = "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>
    public static void CreateXlsFromDataTable(DataTable dataTable, string fullFilePath)
    {
        string createTableWithHeaderScript = GenerateCreateTableCommand(dataTable);

        using (var conn = new OleDbConnection(String.Format(ExcelOleDbConnectionStringTemplate, fullFilePath)))
        {
            if (conn.State != ConnectionState.Open)
            {
                conn.Open();
            }

            OleDbCommand cmd = new OleDbCommand(createTableWithHeaderScript, conn);
            cmd.ExecuteNonQuery();

            foreach (DataRow dataExportRow in dataTable.Rows)
            {
                AddNewRow(conn, dataExportRow);
            }
        }
    }

    private static void AddNewRow(OleDbConnection conn, DataRow dataRow)
    {
        string insertCmd = GenerateInsertRowCommand(dataRow);

        using (OleDbCommand cmd = new OleDbCommand(insertCmd, conn))
        {
            AddParametersWithValue(cmd, dataRow);
            cmd.ExecuteNonQuery();
        }
    }

    /// <summary>
    /// Generates the insert row command.
    /// </summary>
    private static string GenerateInsertRowCommand(DataRow dataRow)
    {
        var stringBuilder = new StringBuilder();
        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>
    private static void AddParametersWithValue(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
            {
                object value = GetParameterValue(dataRow[i]);
                OleDbParameter parameter = cmd.Parameters.AddWithValue("@p" + paramNumber, value);
                if (value is decimal)
                {
                    parameter.OleDbType = OleDbType.Currency;
                }
            }

            paramNumber = paramNumber + 1;
        }
    }

    /// <summary>
    /// Gets the formatted value for the OleDbParameter.
    /// </summary>
    private static object GetParameterValue(object value)
    {
        if (value is string)
        {
            return value.ToString().Replace("'", "''");
        }
        return value;
    }

    private static string GenerateCreateTableCommand(DataTable tableDefination)
    {
        StringBuilder stringBuilder = new StringBuilder();
        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();
    }
}
0 голосов
/ 25 августа 2015

Excel Interop:

Этот метод предотвращает переворачивание дат с дд-мм-гггг на мм-дд-гггг

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;
}

Если вас не волнует, что даты перевернуты, используйте ссылку see, которая показывает, как заполнить все ячейки электронной таблицы Excel одной строкой кода:

Взаимодействие Excel -Эффективность и производительность

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 голосов
/ 20 августа 2015

Старый поток - но думал, что я добавлю сюда свой код.Я написал небольшую функцию для записи таблицы данных на новый лист Excel по указанному пути (местоположению).Также вам нужно будет добавить ссылку на библиотеку Microsoft Excel 14.0.

Я вытащил из этой темы написание чего-либо, чтобы преуспеть - Как записать некоторые данные в файл Excel (.xlsx)

Я использовал это, чтобы экстраполировать, как написатьdatatable

* примечание в операторах catch У меня есть ссылка на статический класс обработчика ошибок (вы можете игнорировать их)

 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 голосов
/ 08 марта 2014

Относительно ответа tuncalik , который великолепен, особенно если вы хотите немного поиграть с кодом :), но он помещает мои даты в Excel в американском формате, то есть 2 марта 2014 года в Великобритания - 02/03/2014, но в США - 03.02.2014 с 1-м месяцем, затем днем ​​недели после. Мне нужно иметь его в британском формате, есть идеи, пожалуйста?

Я проверил, что он хранится в британском формате в моей DataTable, а также в моем Excel установлено значение UK, но по какой-то причине, когда он создает документ Excel, он считает, что его США (это потому, что Microsoft - компания из США:)

Я попытаюсь поэкспериментировать с кодами культуры, но пока не уверен, куда это поставить. Пробовал, но это не имело никакого эффекта.

приписка

Мне пришлось изменить одну строку, чтобы заставить ее работать, добавив «приведение», как показано ниже

// single worksheet
Excel._Worksheet workSheet = (Excel._Worksheet)excelApp.ActiveSheet;

Обновление: я достиг форматирования дат в Великобритании, переведя в формат LongDateTime, хотя это только обходной путь.

DateTime startDate = Convert.ToDateTime(myList[0].ToString());
string strStartDate = startDate.ToLongDateString();
DateTime endDate = Convert.ToDateTime(myList[myListTotalRows].ToString());
string strEndDate = endDate.ToLongDateString();    

веселит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...