C# (WinForms-App) eksport zbioru danych do Excela

Potrzebuję rozwiązania, aby wyeksportować zestaw danych do pliku excel bez kodu asp (HttpResonpsne...), ale nie znalazłem na to dobrego przykładu...

Najlepsze dzięki z góry

Author: maveonair, 2008-12-17

8 answers

Utworzyłem klasę, która eksportuje DataGridView lub DataTable do pliku Excel. Prawdopodobnie możesz go trochę zmienić, aby zamiast tego użyć swojego DataSet (iteracja przez DataTables w nim). Wykonuje również podstawowe formatowanie, które można również rozszerzyć.

Aby go użyć, po prostu wywołaj ExcelExport i określ nazwę pliku oraz czy ma otworzyć plik automatycznie, czy nie po wyeksportowaniu. Mogłem też stworzyć metody rozszerzania, ale nie zrobiłem tego.

Zauważ, że pliki Excela mogą być zapisany jako dokument XML, a to z tego korzysta.

EDIT: to używało wanilii StreamWriter, ale jak już zauważyliśmy, w wielu przypadkach nie można było poprawnie uciec. Teraz używa XmlWriter, która zrobi za Ciebie ucieczkę.

Klasa ExcelWriter otacza XmlWriter. Nie zawracałem sobie głowy, ale możesz chcieć zrobić trochę więcej sprawdzania błędów, aby upewnić się, że nie możesz zapisać danych komórki przed rozpoczęciem wiersza i tym podobne. Kod znajduje się poniżej.

public class ExcelWriter : IDisposable
{
    private XmlWriter _writer;

    public enum CellStyle { General, Number, Currency, DateTime, ShortDate };

    public void WriteStartDocument()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteProcessingInstruction("mso-application", "progid=\"Excel.Sheet\"");
        _writer.WriteStartElement("ss", "Workbook", "urn:schemas-microsoft-com:office:spreadsheet");
         WriteExcelStyles();
   }

    public void WriteEndDocument()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteEndElement();
    }

    private void WriteExcelStyleElement(CellStyle style)
    {
        _writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
        _writer.WriteEndElement();
    }

    private void WriteExcelStyleElement(CellStyle style, string NumberFormat)
    {
        _writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");

        _writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
        _writer.WriteStartElement("NumberFormat", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("Format", "urn:schemas-microsoft-com:office:spreadsheet", NumberFormat);
        _writer.WriteEndElement();

        _writer.WriteEndElement();

    }

    private void WriteExcelStyles()
    {
        _writer.WriteStartElement("Styles", "urn:schemas-microsoft-com:office:spreadsheet");

        WriteExcelStyleElement(CellStyle.General);
        WriteExcelStyleElement(CellStyle.Number, "General Number");
        WriteExcelStyleElement(CellStyle.DateTime, "General Date");
        WriteExcelStyleElement(CellStyle.Currency, "Currency");
        WriteExcelStyleElement(CellStyle.ShortDate, "Short Date");

        _writer.WriteEndElement();
    }

    public void WriteStartWorksheet(string name)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Worksheet", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("Name", "urn:schemas-microsoft-com:office:spreadsheet", name);
        _writer.WriteStartElement("Table", "urn:schemas-microsoft-com:office:spreadsheet");
    }

    public void WriteEndWorksheet()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteEndElement();
        _writer.WriteEndElement();
    }

    public ExcelWriter(string outputFileName)
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        _writer = XmlWriter.Create(outputFileName, settings);
    }

    public void Close()
    {
        if (_writer == null) throw new InvalidOperationException("Already closed.");

        _writer.Close();
        _writer = null;
    }

    public void WriteExcelColumnDefinition(int columnWidth)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Column", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteStartAttribute("Width", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteValue(columnWidth);
        _writer.WriteEndAttribute();
        _writer.WriteEndElement();
    }

    public void WriteExcelUnstyledCell(string value)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
        _writer.WriteValue(value);
        _writer.WriteEndElement();
        _writer.WriteEndElement();
    }

    public void WriteStartRow()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Row", "urn:schemas-microsoft-com:office:spreadsheet");
    }

    public void WriteEndRow()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteEndElement();
    }

    public void WriteExcelStyledCell(object value, CellStyle style)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("StyleID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
        _writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
        switch (style)
        {
            case CellStyle.General:
                _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
                break;
            case CellStyle.Number:
            case CellStyle.Currency:
                _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "Number");
                break;
            case CellStyle.ShortDate:
            case CellStyle.DateTime:
                _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "DateTime");
                break;
        }
        _writer.WriteValue(value);
        //  tag += String.Format("{1}\"><ss:Data ss:Type=\"DateTime\">{0:yyyy\\-MM\\-dd\\THH\\:mm\\:ss\\.fff}</ss:Data>", value,

        _writer.WriteEndElement();
        _writer.WriteEndElement();
    }

    public void WriteExcelAutoStyledCell(object value)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        //write the <ss:Cell> and <ss:Data> tags for something
        if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
            value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
        {
            WriteExcelStyledCell(value, CellStyle.Number);
        }
        else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
        {
            WriteExcelStyledCell(value, CellStyle.Currency);
        }
        else if (value is DateTime)
        {
            //check if there's no time information and use the appropriate style
            WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
        }
        else
        {
            WriteExcelStyledCell(value, CellStyle.General);
        }
    }

    #region IDisposable Members

    public void Dispose()
    {
        if (_writer == null)
            return;

        _writer.Close();
        _writer = null;
    }

    #endregion
}

Następnie można eksportować Twoje DataTable używając następującego:

public static void ExcelExport(DataTable data, String fileName, bool openAfter)
{
    //export a DataTable to Excel
    DialogResult retry = DialogResult.Retry;

    while (retry == DialogResult.Retry)
    {
        try
        {
            using (ExcelWriter writer = new ExcelWriter(fileName))
            {
                writer.WriteStartDocument();

                // Write the worksheet contents
                writer.WriteStartWorksheet("Sheet1");

                //Write header row
                writer.WriteStartRow();
                foreach (DataColumn col in data.Columns)
                    writer.WriteExcelUnstyledCell(col.Caption);
                writer.WriteEndRow();

                //write data
                foreach (DataRow row in data.Rows)
                {
                    writer.WriteStartRow();
                    foreach (object o in row.ItemArray)
                    {
                        writer.WriteExcelAutoStyledCell(o);
                    }
                    writer.WriteEndRow();
                }

                // Close up the document
                writer.WriteEndWorksheet();
                writer.WriteEndDocument();
                writer.Close();
                if (openAfter)
                    OpenFile(fileName);
                retry = DialogResult.Cancel;
            }
        }
        catch (Exception myException)
        {
            retry = MessageBox.Show(myException.Message, "Excel Export", MessageBoxButtons.RetryCancel, MessageBoxIcon.Asterisk);
        }
    }
}
 36
Author: lc.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-13 13:46:10

Poniższa strona pokazuje, jak wyeksportować zestaw danych (lub DataTable lub listę) do " oryginalnego " Excel 2007 .plik xlsx.

Używa bibliotek OpenXML , więc nie musisz mieć zainstalowanego Excela na swoim serwerze.

MikesKnowledgeBase-ExportToExcel

Cały kod źródłowy jest dostarczany, bezpłatnie , a także jako aplikacja demonstracyjna.

To bardzo łatwe dodawanie do własnych aplikacji, po prostu trzeba wywołać jedną funkcję, przekazując nazwę pliku Excel i źródło danych:

DataSet ds = CreateSampleData();
string excelFilename = "C:\\Sample.xlsx";
CreateExcelFile.CreateExcelDocument(ds, excelFilename);
Mam nadzieję, że to pomoże.
 3
Author: Mike Gledhill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-01 13:04:48

Tworzenie plików excel w aplikacjach. NET jest dość powszechne i podobne pytania zadawano już kilka razy. Na przykład tutaj i Tutaj. Ostatnie pytanie dotyczy czytania plików Excela, ale większość sugerowanych rozwiązań powinna działać w obie strony.

 1
Author: Rune Grimstad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:53:14
using XL = Microsoft.Office.Interop.Excel;
using System.Reflection;

public static void Datasource(DataTable dt)
        {

            XL.Application oXL;

            XL._Workbook oWB;

            XL._Worksheet oSheet;

            XL.Range oRng;


            try
            {
                oXL = new XL.Application();

                Application.DoEvents();

                oXL.Visible = false;

                //Get a new workbook.

                oWB = (XL._Workbook)(oXL.Workbooks.Add(Missing.Value));

                oSheet = (XL._Worksheet)oWB.ActiveSheet;

                //System.Data.DataTable dtGridData=ds.Tables[0];


                int iRow = 2;

                if (dt.Rows.Count > 0)
                {


                    for (int j = 0; j < dt.Columns.Count; j++)
                    {

                        oSheet.Cells[1, j + 1] = dt.Columns[j].ColumnName;

                    }

                    // For each row, print the values of each column.

                    for (int rowNo = 0; rowNo < dt.Rows.Count; rowNo++)
                    {

                        for (int colNo = 0; colNo < dt.Columns.Count; colNo++)
                        {

                            oSheet.Cells[iRow, colNo + 1] = dt.Rows[rowNo][colNo].ToString();

                        }
                        iRow++;

                    }

                    iRow++;

                }

                oRng = oSheet.get_Range("A1", "IV1");

                oRng.EntireColumn.AutoFit();

                oXL.Visible = true;

            }

            catch (Exception theException)
            {

                throw theException;

            }
            finally
            {
                oXL = null;

                oWB = null;

                oSheet = null;

                oRng = null;
            }

        }

Import from Excel to datatable

 DataTable dtTable = new DataTable();
            DataColumn col = new DataColumn("Rfid");
            dtTable.Columns.Add(col);
            DataRow drRow;

                Microsoft.Office.Interop.Excel.Application ExcelObj =
                    new Microsoft.Office.Interop.Excel.Application();
                Microsoft.Office.Interop.Excel.Workbook theWorkbook =
                        ExcelObj.Workbooks.Open(txt_FilePath.Text, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                Microsoft.Office.Interop.Excel.Sheets sheets = theWorkbook.Worksheets;
                try
                {
                    for (int sht = 1; sht <= sheets.Count; sht++)
                   {
                        Microsoft.Office.Interop.Excel.Worksheet worksheet =
                                (Microsoft.Office.Interop.Excel.Worksheet)sheets.get_Item(sht);

                        for (int i = 2; i <= worksheet.UsedRange.Rows.Count; i++)
                        {
                            Microsoft.Office.Interop.Excel.Range range = worksheet.get_Range("A" + i.ToString(), "B" + i.ToString());
                            System.Array myvalues = (System.Array)range.Cells.Value2;
                            String name = Convert.ToString(myvalues.GetValue(1, 1));
                            if (string.IsNullOrEmpty(name) == false)
                            {
                                drRow = dtTable.NewRow();
                                drRow["Rfid"] = name;
                                dtTable.Rows.Add(drRow);
                            }
                        }
                        Marshal.ReleaseComObject(worksheet);
                        worksheet = null;
                    }
                return dtTable;

            }
            catch
            {
                throw;
            }
            finally
            {
               // Marshal.ReleaseComObject(worksheet);
                Marshal.ReleaseComObject(sheets);
                Marshal.ReleaseComObject(theWorkbook);
                Marshal.ReleaseComObject(ExcelObj);
                //worksheet = null;
                sheets = null;
                theWorkbook = null;
                ExcelObj = null;
            }
 1
Author: user1314323,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-05 04:21:46

To był post z naprawdę pomocną najlepszą odpowiedzią, ale okazało się, że brakowało, ponieważ nie było prostego sposobu na importowanie pliku XML z powrotem do datatable. Skończyło się na tym, że musiałem napisać swój własny i pomyślałem, że podzielę się nim tutaj, na wypadek, gdyby ktoś inny był w tej samej łodzi (google było wyjątkowo nieprzydatne w tym zakresie): {]}

public static DataTable ImportExcelXML(string Filename)
    {
        //create a new dataset to load in the XML file
        DataSet DS = new DataSet();
        //Read the XML file into the dataset
        DS.ReadXml(Filename);
        //Create a new datatable to store the raw Data
        DataTable Raw = new DataTable();
        //assign the raw data from the file to the datatable
        Raw = DS.Tables["Data"];
        //count the number of columns in the XML file
        int ColumnNumber = Raw.Columns.Count;
        //create a datatable to store formatted Import Data
        DataTable ImportData = new DataTable();
        //create a string list to store the cell data of each row
        List<string> RowData = new List<string>();
        //loop through each row in the raw data table
        for (int Counter = 0; Counter < Raw.Rows.Count; Counter++)
        {
            //if the data in the row is a colum header
            if (Counter < ColumnNumber)
            {
                //add the column name to our formatted datatable
                ImportData.Columns.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
            }
            else
            {
                //if the row # (1 row = 1 cell from the excel file) from the raw datatable is divisable evenly by the number of columns in the formated import datatable AND this is not the 1st row of the raw table data after the headers
                if ((Counter % ColumnNumber == 0) && (Counter != ColumnNumber))
                {
                    //add the row we just built to the formatted import datatable
                    ImportData.Rows.Add(GenerateRow(ImportData, RowData));
                    //clear rowdata list in preperation for the next row
                    RowData.Clear();
                }
                //add the current cell data value from the raw datatable to the string list of cell values for the next row to be added to the formatted input datatable
                RowData.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
            }
        }
        //add the final row
        ImportData.Rows.Add(GenerateRow(ImportData, RowData));

        return ImportData;
    }

    public static DataRow GenerateRow(DataTable ImportData, List<string> RowData)
    {
        //create a counter to keep track of the column position during row composition
        int ColumnPosition = 0;
        //make a new datarow based on the schema of the formated import datatable
        DataRow NewRow = ImportData.NewRow();
        //for each string cell value collected for the RowData list for this row
        foreach (string CellData in RowData)
        {
            //add the cell value to the new datarow
            NewRow[ImportData.Columns[ColumnPosition].ColumnName] = CellData;
            //incriment column position in the new row
            ColumnPosition++;
        }
        //return the generated row
        return NewRow;
    }
 1
Author: Adamantine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-15 18:04:31

Kod ma problem z wartościami null.

 public void WriteExcelAutoStyledCell(object value)
    {
        //solve null values
        if (value is DBNull) return;
 1
Author: user2882267,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-15 11:15:01

Dodałbym to do komentarzy, ale jestem nowy w stosie, więc nie mogę skomentować. Korzystanie z lc.rozwiązanie dodałem kolejną funkcję, która sprawdza znaki łańcuchów pod kątem nieprawidłowych znaków XML. Kiedy eksportowałem do Excela, czasami pojawiały się znaki, które powodowały, że eksport nie powiódł się.

Będziesz musiał zmodyfikować jedną z funkcji, która jest w kodzie lc.

public void WriteExcelAutoStyledCell(object value)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
        string newValue = string.Empty;

        try
        {
            //write the <ss:Cell> and <ss:Data> tags for something
            if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
                value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
            {
                WriteExcelStyledCell(value, CellStyle.Number);
            }
            else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
            {
                WriteExcelStyledCell(value, CellStyle.Currency);
            }
            else if (value is DateTime)
            {
                //check if there's no time information and use the appropriate style
                WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
            }
            else
            {
                newValue = CheckXmlCompatibleValues(value.ToString()).ToString();
                WriteExcelStyledCell(newValue, CellStyle.General);
            }
        }
        catch (Exception thisException)
        {
            throw new InvalidOperationException(thisException.Message.ToString());
        }
    }

I dodać tę funkcję do klasy 'ExcelWriter'

public string CheckXmlCompatibleValues(string value)
    {
        string newValue = string.Empty;
        bool found = false;

        foreach (char c in value)
        {
            if (XmlConvert.IsXmlChar(c))
                newValue += c.ToString();
            else
                found = true;
        }

        return newValue.ToString();
    }

Lc. Dzięki za kod!

 1
Author: lwsolutions,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-09 16:23:53

Microsoft ma wbudowane rozwiązanie do importowania / eksportowania plików Excel. Nie jest to najprostsza biblioteka, ale ogólnie działa lepiej niż inne wymienione powyżej.

Wymagana do tego Biblioteka znajduje się w pakiecie Office i można ją znaleźć na liście zestawów frameworków w firmie Microsoft.Biuro.Interop.Excel.

Oto przykładowy kod:

using Excel = Microsoft.Office.Interop.Excel;

Excel.Application app = new Excel.Application();

//Open existing workbook
//Excel.Workbook workbook = xlApp.Workbooks.Open(fileName);

//Create new workbook
Excel.Workbook workbook = app.Workbooks.Add();

Excel.Worksheet worksheet = workbook.ActiveSheet;

worksheet.Cells[1,1] = "Hello world!"; // Indexes start at 1, because Excel
workbook.SaveAs("C:\\MyWorkbook.xlsx");
workbook.Close();
app.Quit();
 0
Author: DamienMann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-14 15:41:37