簡體   English   中英

使用OLEDB從Excel導入時,數據被截斷了,有哪些替代方法?

[英]Data truncated while importing from Excel using OLEDB, what are the alternatives?

我有一個WPF應用程序,其中具有從Excel讀取數據的功能。 我正在使用OLEDB進行此操作,並且運行良好,直到發現列數限制為255,除非前八行中的數據不超過255個字符,否則數據將被截斷。 解決此問題的方法是更新注冊表,這意味着更新所有用戶的注冊表。 所以我不想采用這種方法。

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工作表中不固定。

如果您使用的是xlsx文件,建議您切換到OfficeOpen XML SDK ,它的性能比OLEDB或Interop的連接方法好得多。

但是,有些人認為SDK難以使用,因此有第三方軟件包可以將SDK打包成一個更友好的界面,但是就我個人而言,我覺得SDK不太難做。

感謝您的答復。這是我使用的最終代碼:參考鏈接: 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;
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM