2008-12-17 71 views

回答

35

我已經創建了一個出口或DataGridViewDataTable到Excel文件中的類。您可以稍微改變它以使其使用您的DataSet代替(迭代其中的DataTables)。它也做一些基本的格式化,你也可以擴展。

要使用它,只需調用ExcelExport,然後指定文件名以及是否在導出後自動打開文件。我也可以讓它們成爲擴展方法,但我沒有。隨意地。

請注意,Excel文件可以保存爲一個榮耀的XML文檔,並利用它。

編輯:這用來使用香草StreamWriter,但指出,事情就不能正確地在許多情況下逃脫了。現在它使用一個XmlWriter,它會爲你逃跑。

ExcelWriter類包裝XmlWriter。我沒有打擾過,但是你可能想要做更多的錯誤檢查,以確保你在開始一行之前不能寫入單元格數據,等等。代碼如下。

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 
} 

然後你可以使用以下導出DataTable

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:不要試圖以這種方式使用的TextWriter生成XML。我只想指出一個顯而易見的問題:如果DataTable包含帶尖括號的字符串值,則上面的代碼不會正確地轉義它們。 – Joe 2008-12-17 10:12:30

+1

好點。只是表明我應該停下來思考更多。我已經重寫了它來使用XmlWriter。從理論上講,在公共圖書館發佈之前,應該做更多的錯誤檢查,但是如果你確定你會按照正確的順序打電話給你,那麼你就「安全」了。 – 2008-12-17 14:56:31

+0

代碼的第二部分存在錯誤。而不是'foreach(dataTable.Rows中的對象o)'應該是'foreach(row.ItemArray中的對象o)'。 – Aleris 2009-01-14 09:17:58

1

.NET應用程序中創建Excel文件是相當普遍,類似的問題已經被問過多次。例如herehere。最後一個問題是關於閱讀excel文件的問題,但大多數建議的解決方案應該可以同時工作。

3

以下網站演示瞭如何將DataSet(或DataTable或列表<>)導出到「真正」Excel 2007 .xlsx文件中。

它使用的OpenXML庫,所以你需要有您的服務器上安裝Excel。

MikesKnowledgeBase - ExportToExcel

所有的源代碼的

設置,免費的,藏漢作爲演示應用程序。

這是非常容易添加到自己的應用程序,你只需要調用一個函數,傳入一個Excel文件名,並且您的數據源:

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

希望這有助於。

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

這是一個真正有用的最多的回答後,但我發現它是缺乏因爲有要導入的XML文件回一個DataTable沒有簡單的方法。我最後不得不寫我自己的,以爲我會在這裏分享萬一別人是在同一條船上(谷歌在這方面是非常無益):

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

的代碼有問題,空值。

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

我已經加入這個意見,但我新的堆棧,所以我無法評論。使用lc。的解決方案,我添加了另一個函數來測試字符串字符是否爲無效的XML字符。當我偶爾導出excel時,會發現導致導出失敗的字符。

您將需要修改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()); 
     } 
    } 

而這個函數添加到 '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。感謝代碼!

0

Microsoft內置了導入/導出Excel文件的解決方案。這不是最直接的庫,但它通常比上面列出的其他庫更好。

執行此操作所需的庫包含在Office中,可以在Microsoft.Office.Interop.Excel的框架程序集列表中找到。

下面是一些示例代碼:

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