2011-08-30 61 views
20

我想做什麼

我試圖使用Microsoft.Office.Interop.Excel namespace打開一個Excel文件(XSL或CSV,但遺憾的是沒有 XSLX),並將其導入的數據集。我無法控制工作表或列名,所以我需要允許對它們進行更改。如何使用Microsoft.Office.Interop.Excel從Excel導入到DataSet?

我已經試過

我已經試過這樣的OLEDB method過去,並且有很多的問題,它(越野車,速度慢,所需的Excel文件的架構的先驗知識),所以我想避免再這樣做。我想要做的是使用Microsoft.Office.Interop.Excel將工作簿直接導入到DataSet,或循環通過工作表並將每個工作表加載到DataTable中。

不管你信不信,我一直無法找到相關資源。 A few searches on StackOverflow已經發現大多數人試圖做相反的事情(DataSet => Excel)或OLEDB技術。谷歌沒有多大幫助。

我有什麼到目前爲止

public void Load(string filename, Excel.XlFileFormat format = Excel.XlFileFormat.xlCSV) 
    { 
     app = new Excel.Application(); 
     book = app.Workbooks.Open(Filename: filename, Format: format); 

     DataSet ds = new DataSet(); 

     foreach (Excel.Worksheet sheet in book.Sheets) 
     { 
      DataTable dt = new DataTable(sheet.Name); 
      ds.Tables.Add(dt); 

      //??? Fill dt from sheet 
     } 

     this.Data = ds; 
    } 

我很好無論是在一次導入整個書,還是通過一個片一次循環。我可以用Interop.Excel做到這一點嗎?

+0

添加賞金,因爲我真的很想知道,如果Interop.Excel有這個能力。如果任何人都可以在不事先了解Excel文件內容的情況下以自動方式獲取數據,我將獎勵賞金。 –

+0

這是可能的_if_你可以事先保證數據。我擔心的是,你希望有一些工作可以用於任何舊的工作簿,並將表格數據提取出來。該表格數據或者需要按照命名範圍來劃分,或者它必須遵循某種約定。如果遵循約定,工作簿中的每張工作表都與第1行中的標題行完全相同,那麼這將成爲可能。否則,你會運氣不好...... – adamleerich

回答

31

如何使用Excel Data Reader(以前承載here)codeplex上的開源項目?它的工作非常適合我從Excel表導出數據。

指定的鏈接中給出的樣本代碼:

FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read); 

//1. Reading from a binary Excel file ('97-2003 format; *.xls) 
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream); 
//... 
//2. Reading from a OpenXml Excel file (2007 format; *.xlsx) 
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream); 
//... 
//3. DataSet - The result of each spreadsheet will be created in the result.Tables 
DataSet result = excelReader.AsDataSet(); 
//... 
//4. DataSet - Create column names from first row 
excelReader.IsFirstRowAsColumnNames = true; 
DataSet result = excelReader.AsDataSet(); 

//5. Data Reader methods 
while (excelReader.Read()) 
{ 
//excelReader.GetInt32(0); 
} 

//6. Free resources (IExcelDataReader is IDisposable) 
excelReader.Close(); 

UPDATE

周圍的一些搜索後,我遇到了這篇文章:Faster MS Excel Reading using Office Interop Assemblies。該文章僅使用Office Interop Assemblies從給定的Excel工作表讀取數據。源代碼是該項目也在那裏。我想這篇文章可以成爲你嘗試實現的起點。看看是否有幫助

更新2

下面的代碼需要一個excel workbook並讀取找到的所有值,每個excel worksheetexcel workbook內。

private static void TestExcel() 
    { 
     ApplicationClass app = new ApplicationClass(); 
     Workbook book = null; 
     Range range = null; 

     try 
     { 
      app.Visible = false; 
      app.ScreenUpdating = false; 
      app.DisplayAlerts = false; 

      string execPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); 

      book = app.Workbooks.Open(@"C:\data.xls", Missing.Value, Missing.Value, Missing.Value 
               , Missing.Value, Missing.Value, Missing.Value, Missing.Value 
              , Missing.Value, Missing.Value, Missing.Value, Missing.Value 
              , Missing.Value, Missing.Value, Missing.Value); 
      foreach (Worksheet sheet in book.Worksheets) 
      { 

       Console.WriteLine(@"Values for Sheet "+sheet.Index); 

       // get a range to work with 
       range = sheet.get_Range("A1", Missing.Value); 
       // get the end of values to the right (will stop at the first empty cell) 
       range = range.get_End(XlDirection.xlToRight); 
       // get the end of values toward the bottom, looking in the last column (will stop at first empty cell) 
       range = range.get_End(XlDirection.xlDown); 

       // get the address of the bottom, right cell 
       string downAddress = range.get_Address(
        false, false, XlReferenceStyle.xlA1, 
        Type.Missing, Type.Missing); 

       // Get the range, then values from a1 
       range = sheet.get_Range("A1", downAddress); 
       object[,] values = (object[,]) range.Value2; 

       // View the values 
       Console.Write("\t"); 
       Console.WriteLine(); 
       for (int i = 1; i <= values.GetLength(0); i++) 
       { 
        for (int j = 1; j <= values.GetLength(1); j++) 
        { 
         Console.Write("{0}\t", values[i, j]); 
        } 
        Console.WriteLine(); 
       } 
      } 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
     finally 
     { 
      range = null; 
      if (book != null) 
       book.Close(false, Missing.Value, Missing.Value); 
      book = null; 
      if (app != null) 
       app.Quit(); 
      app = null; 
     } 
    } 

在上面的代碼,values[i, j]是,你需要添加到dataset值。 i表示該行,而j表示該列。

+0

如果可能的話,我仍然傾向於使用Interop.Excel,但這是一個很棒的備份計劃。謝謝。 –

+1

如果您發現與Interop.Excel相關的內容,請在此處張貼。基於此做一些事情也不錯。 – reggie

+0

@Justin Morgan我用CodeProject上的一篇文章鏈接更新了答案,該文章僅使用Office Interop程序集。讓我知道這是否有幫助。 – reggie

4

你見過這個嗎?從http://www.aspspider.com/resources/Resource510.aspx

public DataTable Import(String path) 
{ 
    Microsoft.Office.Interop.Excel.ApplicationClass app = new Microsoft.Office.Interop.Excel.ApplicationClass(); 
    Microsoft.Office.Interop.Excel.Workbook workBook = app.Workbooks.Open(path, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); 

    Microsoft.Office.Interop.Excel.Worksheet workSheet = (Microsoft.Office.Interop.Excel.Worksheet)workBook.ActiveSheet; 

    int index = 0; 
    object rowIndex = 2; 

    DataTable dt = new DataTable(); 
    dt.Columns.Add("FirstName"); 
    dt.Columns.Add("LastName"); 
    dt.Columns.Add("Mobile"); 
    dt.Columns.Add("Landline"); 
    dt.Columns.Add("Email"); 
    dt.Columns.Add("ID"); 

    DataRow row; 

    while (((Microsoft.Office.Interop.Excel.Range)workSheet.Cells[rowIndex, 1]).Value2 != null) 
    { 
     rowIndex = 2 + index; 
     row = dt.NewRow(); 
     row[0] = Convert.ToString(((Microsoft.Office.Interop.Excel.Range)workSheet.Cells[rowIndex, 1]).Value2); 
     row[1] = Convert.ToString(((Microsoft.Office.Interop.Excel.Range)workSheet.Cells[rowIndex, 2]).Value2); 
     row[2] = Convert.ToString(((Microsoft.Office.Interop.Excel.Range)workSheet.Cells[rowIndex, 3]).Value2); 
     row[3] = Convert.ToString(((Microsoft.Office.Interop.Excel.Range)workSheet.Cells[rowIndex, 4]).Value2); 
     row[4] = Convert.ToString(((Microsoft.Office.Interop.Excel.Range)workSheet.Cells[rowIndex, 5]).Value2); 
     index++; 
     dt.Rows.Add(row); 
    } 
    app.Workbooks.Close(); 
    return dt; 
} 
+0

我大概可以適應這一點。我不知道列數或數據類型,所以我必須找到解決方法。我希望Interop.Excel中有一些實際上允許直接轉換爲某個數據對象的東西,但我會盡我所能。 –

+0

Interop.Excel不允許從一種數據類型直接轉換爲另一種數據類型。它將使您能夠訪問Sheets對象,以便訪問每個工作表,然後遍歷該工作表中的每個範圍,但就是這樣。一旦你在那裏,你將不得不編寫轉換代碼。 – adamleerich

+0

這段代碼看起來非常結構化。我們是否有擴展來更新excel? – Shalem

4
object[,] valueArray = (object[,])excelRange.get_Value(XlRangeValueDataType.xlRangeValueDefault); 

//Get the column names 
for (int k = 0; k < valueArray.GetLength(1);) 
{ 
    //add columns to the data table. 
    dt.Columns.Add((string)valueArray[1,++k]); 
} 

//Load data into data table 
object[] singleDValue = new object[valueArray.GetLength(1)]; 
//value array first row contains column names. so loop starts from 1 instead of 0 
for (int i = 1; i < valueArray.GetLength(0); i++) 
{ 
    Console.WriteLine(valueArray.GetLength(0) + ":" + valueArray.GetLength(1)); 
    for (int k = 0; k < valueArray.GetLength(1);) 
    { 
     singleDValue[k] = valueArray[i+1, ++k]; 
    } 
    dt.LoadDataRow(singleDValue, System.Data.LoadOption.PreserveChanges); 
} 
+0

不錯,又快又好。謝謝。 –

1
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data; 
using System.Reflection; 
using Microsoft.Office.Interop.Excel; 

namespace trg.satmap.portal.ParseAgentSkillMapping 
{ 
    class ConvertXLStoDT 
    { 
     private StringBuilder errorMessages; 

     public StringBuilder ErrorMessages 
     { 
      get { return errorMessages; } 
      set { errorMessages = value; } 
     } 

     public ConvertXLStoDT() 
     { 
      ErrorMessages = new StringBuilder(); 
     } 

     public System.Data.DataTable XLStoDTusingInterOp(string FilePath) 
     { 
      #region Excel important Note. 
      /* 
      * Excel creates XLS and XLSX files. These files are hard to read in C# programs. 
      * They are handled with the Microsoft.Office.Interop.Excel assembly. 
      * This assembly sometimes creates performance issues. Step-by-step instructions are helpful. 
      * 
      * Add the Microsoft.Office.Interop.Excel assembly by going to Project -> Add Reference. 
      */ 
      #endregion 

      Microsoft.Office.Interop.Excel.Application excelApp = null; 
      Microsoft.Office.Interop.Excel.Workbook workbook = null; 


      System.Data.DataTable dt = new System.Data.DataTable(); //Creating datatable to read the content of the Sheet in File. 

      try 
      { 

       excelApp = new Microsoft.Office.Interop.Excel.Application(); // Initialize a new Excel reader. Must be integrated with an Excel interface object. 

       //Opening Excel file(myData.xlsx) 
       workbook = excelApp.Workbooks.Open(FilePath, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value); 

       Microsoft.Office.Interop.Excel.Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets.get_Item(1); 

       Microsoft.Office.Interop.Excel.Range excelRange = ws.UsedRange; //gives the used cells in sheet 

       ws = null; // now No need of this so should expire. 

       //Reading Excel file.    
       object[,] valueArray = (object[,])excelRange.get_Value(Microsoft.Office.Interop.Excel.XlRangeValueDataType.xlRangeValueDefault); 

       excelRange = null; // you don't need to do any more Interop. Now No need of this so should expire. 

       dt = ProcessObjects(valueArray);     

      } 
      catch (Exception ex) 
      { 
       ErrorMessages.Append(ex.Message); 
      } 
      finally 
      { 
       #region Clean Up     
       if (workbook != null) 
       { 
        #region Clean Up Close the workbook and release all the memory. 
        workbook.Close(false, FilePath, Missing.Value);      
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); 
        #endregion 
       } 
       workbook = null; 

       if (excelApp != null) 
       { 
        excelApp.Quit(); 
       } 
       excelApp = null;     

       #endregion 
      } 
      return (dt); 
     } 

     /// <summary> 
     /// Scan the selected Excel workbook and store the information in the cells 
     /// for this workbook in an object[,] array. Then, call another method 
     /// to process the data. 
     /// </summary> 
     private void ExcelScanIntenal(Microsoft.Office.Interop.Excel.Workbook workBookIn) 
     { 
      // 
      // Get sheet Count and store the number of sheets. 
      // 
      int numSheets = workBookIn.Sheets.Count; 

      // 
      // Iterate through the sheets. They are indexed starting at 1. 
      // 
      for (int sheetNum = 1; sheetNum < numSheets + 1; sheetNum++) 
      { 
       Worksheet sheet = (Worksheet)workBookIn.Sheets[sheetNum]; 

       // 
       // Take the used range of the sheet. Finally, get an object array of all 
       // of the cells in the sheet (their values). You can do things with those 
       // values. See notes about compatibility. 
       // 
       Range excelRange = sheet.UsedRange; 
       object[,] valueArray = (object[,])excelRange.get_Value(XlRangeValueDataType.xlRangeValueDefault); 

       // 
       // Do something with the data in the array with a custom method. 
       // 
       ProcessObjects(valueArray); 
      } 
     } 
     private System.Data.DataTable ProcessObjects(object[,] valueArray) 
     { 
      System.Data.DataTable dt = new System.Data.DataTable(); 

      #region Get the COLUMN names 

      for (int k = 1; k <= valueArray.GetLength(1); k++) 
      { 
       dt.Columns.Add((string)valueArray[1, k]); //add columns to the data table. 
      } 
      #endregion 

      #region Load Excel SHEET DATA into data table 

      object[] singleDValue = new object[valueArray.GetLength(1)]; 
      //value array first row contains column names. so loop starts from 2 instead of 1 
      for (int i = 2; i <= valueArray.GetLength(0); i++) 
      { 
       for (int j = 0; j < valueArray.GetLength(1); j++) 
       { 
        if (valueArray[i, j + 1] != null) 
        { 
         singleDValue[j] = valueArray[i, j + 1].ToString(); 
        } 
        else 
        { 
         singleDValue[j] = valueArray[i, j + 1]; 
        } 
       } 
       dt.LoadDataRow(singleDValue, System.Data.LoadOption.PreserveChanges); 
      } 
      #endregion 


      return (dt); 
     } 
    } 
}