2015-09-22 44 views
0

我有一個WPF應用程序,我有功能從Excel中讀取數據。 我這樣做使用OLEDB,它工作得很好,直到我發現有255的列限制和數據將被截斷,除非數據> 255個字符不存在於前八行。解決此問題的方法是更新註冊表,這意味着更新所有用戶的註冊表。所以我不想這樣做。使用OLEDB從Excel導入數據時截斷數據,有哪些替代方法?

OLEDB代碼:

string strSQL = "SELECT * FROM [Sheet1$]"; 
OleDbCommand cmd = new OleDbCommand(strSQL, conn); 
DataSet ds1 = new DataSet(); 
OleDbDataAdapter da = new OleDbDataAdapter(cmd); 
da.Fill(ds1); 

作爲替代方案,我試圖Interop.Excel。但是,OLEDB似乎比較慢。使用Interop.Excel需要花費2秒鐘的Excel工作表約需15秒鐘。

System.Data.DataTable tempTable = new System.Data.DataTable(); 
tempTable.TableName = "ResultData"; 
Excel.Application app = new Excel.Application(); 
Excel.Workbook book = null; 
Excel.Range range = null; 
try 
{ 
app.Visible = false; 
app.ScreenUpdating = false; 
app.DisplayAlerts = false; 

book = app.Workbooks.Open(inputFilePath, 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 (Excel.Worksheet sheet in book.Worksheets) 
    { 
    Logger.LogException("Values for Sheet " + sheet.Index, System.Reflection.MethodBase.GetCurrentMethod().ToString()); 
    // 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(Excel.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(Excel.XlDirection.xlDown); 

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

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

     //Get the Column Names 
     for (int k = 0; k < values.GetLength(1);) 
     { 
     tempTable.Columns.Add(Convert.ToString(values[1, ++k]).Trim()); 
     } 

     for (int i = 2; i <= values.GetLength(0); i++)//first row contains the column names, so start from the next row. 
     { 
     System.Data.DataRow dr = tempTable.NewRow(); 
     for (int j = 1; j <= values.GetLength(1); j++)//columns 
     { 
      dr[j - 1] = values[i, j]; 
     } 
         tempTable.Rows.Add(dr); 
        } 
       } 

是否有另一種方法與OLEDB一樣快?

列表和行不固定在Excel工作表中。

+0

你處理'xls'文件或'xlsx'文件? –

+0

您可以使用ACE是Microsoft Office驅動程序。 Oledb帶有窗戶,而ACE配有辦公室。我想你可以在沒有辦公室許可證的情況下安裝ACE,但我從來沒有成功完成它。你只需要改變連接字符串。請參閱www.connectionstrings.com。 – jdweng

+0

@ScottChamberlain它是xlsx文件 – perplexedDev

回答

1

感謝您response.Here是,我使用的最終代碼: 參考鏈接:http://www.prowareness.com/blog/reading-data-from-excel-document-using-openxml/

public static DataSet ExtractExcelSheetValuesToDataTable(string xlsxFilePath, string sheetName) 
     { 
      DataTable dt = new DataTable(); 
      DataSet ds = new DataSet(); 
      using (SpreadsheetDocument myWorkbook = SpreadsheetDocument.Open(xlsxFilePath, true)) 
      { 
       //Access the main Workbook part, which contains data 
       WorkbookPart workbookPart = myWorkbook.WorkbookPart; 
       WorksheetPart worksheetPart = null; 
       if (!string.IsNullOrEmpty(sheetName)) 
       { 
        Sheet ss = workbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).SingleOrDefault<Sheet>(); 
        worksheetPart = (WorksheetPart)workbookPart.GetPartById(ss.Id); 
       } 
       else 
       { 
        worksheetPart = workbookPart.WorksheetParts.FirstOrDefault(); 
       } 
       SharedStringTablePart stringTablePart = workbookPart.SharedStringTablePart; 
       if (worksheetPart != null) 
       { 
        Row lastRow = worksheetPart.Worksheet.Descendants<Row>().LastOrDefault(); 
        Row firstRow = worksheetPart.Worksheet.Descendants<Row>().FirstOrDefault(); 
        if (firstRow != null) 
        { 
         foreach (Cell c in firstRow.ChildElements) 
         { 
          string value = GetValue(c, stringTablePart); 
          dt.Columns.Add(value); 
         } 
        } 
        if (lastRow != null) 
        { 
         for (int i = 2; i <= lastRow.RowIndex; i++) 
         { 
          DataRow dr = dt.NewRow(); 
          bool empty = true; 
          Row row = worksheetPart.Worksheet.Descendants<Row>().Where(r => i == r.RowIndex).FirstOrDefault(); 
          int j = 0; 
          if (row != null) 
          { 
           foreach (Cell c in row.Descendants<Cell>()) 
           { 
            int? colIndex = GetColumnIndex(((DocumentFormat.OpenXml.Spreadsheet.CellType)(c)).CellReference); 
            if (colIndex > j) 
            { 
             dr[j] = ""; 
             j++; 
            } 
            //Get cell value 
            string value = GetValue(c, stringTablePart); 
            //if (!string.IsNullOrEmpty(value)) 
            // empty = false; 
            dr[j] = value; 
            j++; 
            if (j == dt.Columns.Count) 
             break; 
           } 

           //foreach (Cell c in row.ChildElements) 
           //{ 
           // //Get cell value 
           // string value = GetValue(c, stringTablePart); 
           // //if (!string.IsNullOrEmpty(value)) 
           // // empty = false; 
           // dr[j] = value; 
           // j++; 
           // if (j == dt.Columns.Count) 
           //  break; 
           //} 
           //if (empty) 
           // break; 
           dt.Rows.Add(dr); 
          } 
         } 
        } 
       } 
      } 
      ds.Tables.Add(dt); 
      return ds; 
     } 
     public static string GetValue(Cell cell, SharedStringTablePart stringTablePart) 
     { 
      if (cell.ChildElements.Count == 0) return null; 
      //get cell value 
      string value = cell.ElementAt(0).InnerText;//CellValue.InnerText; 
      //Look up real value from shared string table 
      if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString)) 
       value = stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText; 
      return value; 
     } 

     private static int? GetColumnIndex(string cellReference) 
     { 
      if (string.IsNullOrEmpty(cellReference)) 
      { 
       return null; 
      } 

      //remove digits 
      string columnReference = Regex.Replace(cellReference.ToUpper(), @"[\d]", string.Empty); 

      int columnNumber = -1; 
      int mulitplier = 1; 

      //working from the end of the letters take the ASCII code less 64 (so A = 1, B =2...etc) 
      //then multiply that number by our multiplier (which starts at 1) 
      //multiply our multiplier by 26 as there are 26 letters 
      foreach (char c in columnReference.ToCharArray().Reverse()) 
      { 
       columnNumber += mulitplier * ((int)c - 64); 

       mulitplier = mulitplier * 26; 
      } 

      //the result is zero based so return columnnumber + 1 for a 1 based answer 
      //this will match Excel's COLUMN function 
      return columnNumber; 
     } 
+1

務必將您的答案標記爲已接受,未接受答案的問題每隔幾個月會自動推送到首頁。 –

1

如果您正在使用xlsx文件,我建議切換到Open XML SDK for Office,它比OLEDB或Interop連接方法執行得更好。

但是,有些人認爲SDK很難使用,所以有3rd party packages將SDK包裝到一個更友好的界面,但我個人覺得SDK不是很難做到。