2008-12-17 43 views
24

Tôi cần giải pháp để xuất tập dữ liệu sang tệp excel mà không cần mã asp (HttpResonpsne ...) nhưng tôi không tìm thấy ví dụ hay để làm điều này ...C# (WinForms-App) xuất DataSet sang Excel

nhờ xuất sắc nhất trước

Trả lời

35

tôi đã tạo ra một lớp học mà xuất khẩu một DataGridView hoặc DataTable vào một tập tin Excel. Bạn có thể thay đổi nó một chút để làm cho nó sử dụng DataSet của bạn thay vào đó (lặp qua DataTables trong đó). Nó cũng làm một số định dạng cơ bản mà bạn cũng có thể mở rộng.

Để sử dụng, chỉ cần gọi ExcelExport và chỉ định tên tệp và liệu có mở tệp tự động hay không sau khi xuất. Tôi cũng có thể đã làm cho họ phương pháp mở rộng, nhưng tôi đã không. Thoải mái để.

Lưu ý rằng các tệp Excel có thể được lưu dưới dạng tài liệu XML được tôn vinh và điều này sử dụng điều đó.

CHỈNH SỬA: Điều này được sử dụng để sử dụng vanilla StreamWriter, nhưng như đã chỉ ra, mọi thứ sẽ không được thoát đúng cách trong nhiều trường hợp. Bây giờ nó sử dụng một XmlWriter, mà sẽ làm thoát cho bạn.

Lớp ExcelWriter kết thúc tốt đẹp một XmlWriter. Tôi đã không làm phiền, nhưng bạn có thể muốn kiểm tra lỗi nhiều hơn một chút để chắc chắn rằng bạn không thể ghi dữ liệu ô trước khi bắt đầu một hàng, và như vậy. Mã dưới đây.

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 
} 

Sau đó, bạn có thể xuất DataTable của bạn bằng cách sử dụng sau đây:

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); 
     } 
    } 
} 
+1

-1: Đừng cố gắng để tạo ra XML sử dụng một TextWriter theo cách này. Tôi sẽ chỉ ra một vấn đề rõ ràng: nếu DataTable của bạn có chứa một giá trị chuỗi với dấu ngoặc nhọn, mã trên sẽ không thoát khỏi chúng đúng cách. – Joe

+1

Điểm tốt. Chỉ cần đi để cho thấy tôi nên dừng lại để suy nghĩ nhiều hơn một chút. Tôi đã làm lại nó để sử dụng một XmlWriter. Về mặt lý thuyết, người ta phải kiểm tra lỗi nhiều hơn một chút trước khi phát hành nó trong một thư viện công cộng, nhưng nếu bạn chắc chắn bạn sẽ gọi mọi thứ theo đúng thứ tự bạn "an toàn". –

+0

Có lỗi trong phần thứ hai của mã. Thay vì 'foreach (đối tượng o trong dataTable.Rows)' nên được 'foreach (đối tượng o trong row.ItemArray)'. – Aleris

1

Tạo file excel trong các ứng dụng .NET là khá phổ biến và các câu hỏi tương tự đã được hỏi nhiều lần trước đó. Ví dụ: herehere. Câu hỏi cuối cùng hỏi về việc đọc các tệp excel, nhưng hầu hết các giải pháp được đề xuất đều hoạt động theo cả hai cách.

+0

Đúng nếu tôi sai, nhưng mave đã yêu cầu một giải pháp không phải trên một máy chủ web? –

+0

Ah. Tôi hiểu lầm câu hỏi của bạn sau đó. Tôi nghĩ rằng bạn đã yêu cầu một cách để làm cho các tập tin excel mà không VIẾT bất kỳ mã nào. Tôi sẽ thuật lại câu trả lời của tôi. –

3

Trang sau đây minh họa cách xuất một Số liệu (hoặc DataTable hoặc Danh sách <>) thành tệp "chính hãng" Excel 2007 .xlsx.

Sử dụng thư viện OpenXML, vì vậy, bạn không cần phải cài đặt Excel trên máy chủ của mình.

MikesKnowledgeBase - ExportToExcel

Tất cả các mã nguồn được cung cấp, miễn phí, là tốt như một ứng dụng demo.

Đó là rất dễ dàng để thêm vào các ứng dụng của riêng bạn, bạn chỉ cần gọi một hàm, đi qua trong một tên tập tin Excel, và nguồn dữ liệu của bạn:

DataSet ds = CreateSampleData(); 
string excelFilename = "C:\\Sample.xlsx"; 
CreateExcelFile.CreateExcelDocument(ds, excelFilename); 

Hope this helps.

+0

Tôi đang sử dụng cái này. Tôi không thể thấy một thỏa thuận cấp phép? – Melanie

1
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; 
      } 
+0

Cố gắng bao gồm một số giải thích cho mã của bạn. –

1

Đây là bài đăng có câu trả lời thực sự hữu ích, nhưng tôi thấy nó thiếu vì không có cách đơn giản nào để nhập tệp XML trở lại vào dữ liệu.Tôi đã kết thúc phải viết của riêng tôi, và nghĩ rằng tôi sẽ chia sẻ nó ở đây trong trường hợp bất cứ ai khác là trong cùng một thuyền (google là đặc biệt vô ích trong vấn đề đó):

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

mã có vấn đề với các giá trị null.

public void WriteExcelAutoStyledCell(object value) 
    { 
     //solve null values 
     if (value is DBNull) return; 
1

Tôi đã thêm điều này vào nhận xét nhưng tôi mới làm quen với ngăn xếp để tôi không thể nhận xét. Sử dụng giải pháp của lc. Tôi đã thêm một hàm khác để kiểm tra các ký tự chuỗi cho các ký tự XML không hợp lệ. Khi tôi được xuất khẩu để xuất sắc nhân dịp có những nhân vật đã được tìm thấy đã gây ra việc xuất khẩu thất bại.

Bạn sẽ cần sửa đổi một trong các chức năng có trong mã của 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()); 
     } 
    } 

Và thêm chức năng này để lớp '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. Cảm ơn mã!

0

Microsoft có giải pháp tích hợp cho việc nhập/xuất tệp Excel. Nó không phải là thư viện đơn giản nhất nhưng nó thường hoạt động tốt hơn so với những người khác được liệt kê ở trên.

Thư viện cần thiết để thực hiện việc này được bao gồm trong Office và có thể được tìm thấy trong danh sách các hội đồng khung tại Microsoft.Office.Interop.Excel.

Dưới đây là một số mã ví dụ:

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(); 
Các vấn đề liên quan