导入大的.xlsx文件非常慢

我是新来的C#和WPF,并试图导入一个大的.xlsx文件到一个数据网格,我可以有大约200 +列和100,000 +行。 用我目前的方法是花了一个多小时(我没有让它完成)。 以csv的forms表示我的格式的一个例子是;

"Time","Dist","V_Front","V_Rear","RPM" "s","m","km/h","km/h","rpm" "0.000","0","30.3","30.0","11995" "0.005","0","30.3","30.0","11965" "0.010","0","30.3","31.0","11962" 

我现在正在使用Interop,但是我想知道是否有另一种方法可以大幅度缩短加载时间。 我希望使用SciCharts(他们有一个学生许可证)绘制这些数据,checkbox用于频道select,但这是另一回事。

.CS

  private void Button_Click(object sender, RoutedEventArgs e) { OpenFileDialog openfile = new OpenFileDialog(); openfile.DefaultExt = ".xlsx"; openfile.Filter = "(.xlsx)|*.xlsx"; var browsefile = openfile.ShowDialog(); if (browsefile == true) { txtFilePath.Text = openfile.FileName; Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application(); Microsoft.Office.Interop.Excel.Workbook excelBook = excelApp.Workbooks.Open(txtFilePath.Text.ToString(), 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); Microsoft.Office.Interop.Excel.Worksheet excelSheet = (Microsoft.Office.Interop.Excel.Worksheet)excelBook.Worksheets.get_Item(1); ; Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange; string strCellData = ""; double douCellData; int rowCnt = 0; int colCnt = 0; DataTable dt = new DataTable(); for (colCnt = 1; colCnt <= excelRange.Columns.Count; colCnt++) { string strColumn = ""; strColumn = (string)(excelRange.Cells[1, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2; dt.Columns.Add(strColumn, typeof(string)); } for (rowCnt = 2; rowCnt <= excelRange.Rows.Count; rowCnt++) { string strData = ""; for (colCnt = 1; colCnt <= excelRange.Columns.Count; colCnt++) { try { strCellData = (string)(excelRange.Cells[rowCnt, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2; strData += strCellData + "|"; } catch (Exception ex) { douCellData = (excelRange.Cells[rowCnt, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2; strData += douCellData.ToString() + "|"; } } strData = strData.Remove(strData.Length - 1, 1); dt.Rows.Add(strData.Split('|')); } dtGrid.ItemsSource = dt.DefaultView; excelBook.Close(true, null, null); excelApp.Quit(); } } 

任何帮助,我真的很感激。

问题是,有太多的个人阅读,导致了Excel和您的应用程序之间的reflection使用和编组大量反映。 如果你不关心内存的使用情况,那么你可以将整个Range读入内存,而不是单独读取单元。 以下代码在包含5列和103938行的testing文件中以3880毫秒运行:

 OpenFileDialog openfile = new OpenFileDialog(); openfile.DefaultExt = ".xlsx"; openfile.Filter = "(.xlsx)|*.xlsx"; var browsefile = openfile.ShowDialog(); if (browsefile == true) { txtFilePath.Text = openfile.FileName; var excelApp = new Microsoft.Office.Interop.Excel.Application(); var excelBook = excelApp.Workbooks.Open(txtFilePath.Text, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); var excelSheet = (Microsoft.Office.Interop.Excel.Worksheet) excelBook.Worksheets.Item[1]; Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange; DataTable dt = new DataTable(); object[,] value = excelRange.Value; int columnsCount = value.GetLength(1); for (var colCnt = 1; colCnt <= columnsCount; colCnt++) { dt.Columns.Add((string)value[1, colCnt], typeof(string)); } int rowsCount = value.GetLength(0); for (var rowCnt = 2; rowCnt <= rowsCount; rowCnt++) { var dataRow = dt.NewRow(); for (var colCnt = 1; colCnt <= columnsCount; colCnt++) { dataRow[colCnt - 1] = value[rowCnt, colCnt]; } dt.Rows.Add(dataRow); } dtGrid.ItemsSource = dt.DefaultView; excelBook.Close(true); excelApp.Quit(); } 

如果你不想阅读整个Range ,那么你应该明智地做到这一点。

另一个优化是在后台线程上运行它,所以在加载时不会阻塞UI。

编辑

为了在后台线程上运行,可以修改button点击处理程序,使其成为一个asynchronous方法,并将parsing逻辑放入另一个方法中,该方法使用Task.Run在线程Task.Run线程上运行实际的parsing:

 private async void Button_Click(object sender, RoutedEventArgs e) { OpenFileDialog openfile = new OpenFileDialog(); openfile.DefaultExt = ".xlsx"; openfile.Filter = "(.xlsx)|*.xlsx"; var browsefile = openfile.ShowDialog(); if (browsefile == true) { txtFilePath.Text = openfile.FileName; DataTable dataTable = await ParseExcel(txtFilePath.Text).ConfigureAwait(true); dtGrid.ItemsSource = dataTable.DefaultView; } } private Task<DataTable> ParseExcel(string filePath) { return Task.Run(() => { var excelApp = new Microsoft.Office.Interop.Excel.Application(); var excelBook = excelApp.Workbooks.Open(filePath, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0); var excelSheet = (Microsoft.Office.Interop.Excel.Worksheet) excelBook.Worksheets.Item[1]; Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange; DataTable dt = new DataTable(); object[,] value = excelRange.Value; int columnsCount = value.GetLength(1); for (var colCnt = 1; colCnt <= columnsCount; colCnt++) { dt.Columns.Add((string) value[1, colCnt], typeof(string)); } int rowsCount = value.GetLength(0); for (var rowCnt = 2; rowCnt <= rowsCount; rowCnt++) { var dataRow = dt.NewRow(); for (var colCnt = 1; colCnt <= columnsCount; colCnt++) { dataRow[colCnt - 1] = value[rowCnt, colCnt]; } dt.Rows.Add(dataRow); } excelBook.Close(true); excelApp.Quit(); return dt; }); } 

处理程序只是调用parsing函数,parsing函数在后台线程上运行,处理程序完成后可以继续将生成的DataTable分配给ItemsSource