如何有效地打开一个巨大的Excel文件

2022-09-01 04:32:48

我有一个150MB的单页Excel文件,使用以下命令在功能非常强大的计算机上打开大约需要7分钟:

# using python
import xlrd
wb = xlrd.open_workbook(file)
sh = wb.sheet_by_index(0)

有没有办法更快地打开Excel文件?我甚至对非常古怪的建议持开放态度(例如hadoop,spark,c,java等)。理想情况下,我正在寻找一种在30秒内打开文件的方法,如果这不是一个白日梦。另外,上面的例子是使用python,但它不一定是python。


注意:这是来自客户端的 Excel 文件。在我们收到它之前,它不能转换为任何其他格式。这不是我们的文件


更新:用一个代码的工作示例来回答,该代码将在30秒内打开以下200MB excel文件,将获得赏金奖励:https://drive.google.com/file/d/0B_CXvCTOo7_2VW9id2VXRWZrbzQ/view?usp=sharing。此文件应包含字符串 (col 1)、date (col 9) 和 number (col 11)。


答案 1

大多数与Office产品一起使用的编程语言都有一些中间层,这通常是瓶颈所在,一个很好的例子是使用PIA的/互操作或Open XML SDK。

在较低级别(绕过中间层)获取数据的一种方法是使用驱动程序。

150MB的单页Excel文件,大约需要7分钟。

我能做的最好的事情就是在135秒内完成一个130MB的文件,大约快3倍:

Stopwatch sw = new Stopwatch();
sw.Start();

DataSet excelDataSet = new DataSet();

string filePath = @"c:\temp\BigBook.xlsx";

// For .XLSXs we use =Microsoft.ACE.OLEDB.12.0;, for .XLS we'd use Microsoft.Jet.OLEDB.4.0; with  "';Extended Properties=\"Excel 8.0;HDR=YES;\"";
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + filePath + "';Extended Properties=\"Excel 12.0;HDR=YES;\"";

using (OleDbConnection conn = new OleDbConnection(connectionString))
{
    conn.Open();
    OleDbDataAdapter objDA = new System.Data.OleDb.OleDbDataAdapter
    ("select * from [Sheet1$]", conn);
    objDA.Fill(excelDataSet);
    //dataGridView1.DataSource = excelDataSet.Tables[0];
}
sw.Stop();
Debug.Print("Load XLSX tool: " + sw.ElapsedMilliseconds + " millisecs. Records = "  + excelDataSet.Tables[0].Rows.Count);

enter image description here

Win 7x64, Intel i5, 2.3ghz, 8GB ram, SSD250GB.

如果我也可以推荐硬件解决方案,如果您使用的是标准HDD,请尝试使用SSD来解决它。

注意:我无法下载您的 Excel 电子表格示例,因为我位于企业防火墙后面。

请参阅MSDN - 导入具有200 MB数据的xlsx文件的最快方法共识是OleDB是最快的。

PS 2.以下是使用python的方法:http://code.activestate.com/recipes/440661-read-tabular-data-from-excel-spreadsheets-the-fast/


答案 2

我设法使用.NET core和Open XML SDK在大约30秒内读取了该文件。

下面的示例返回一个对象列表,其中包含具有匹配类型的所有行和单元格,它支持日期、数字和文本单元格。该项目可在此处获得:https://github.com/xferaa/BigSpreadSheetExample/(应在Windows,Linux和Mac OS上运行,并且不需要安装Excel或任何Excel组件)。

public List<List<object>> ParseSpreadSheet()
{
    List<List<object>> rows = new List<List<object>>();

    using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filePath, false))
    {
        WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
        WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();

        OpenXmlReader reader = OpenXmlReader.Create(worksheetPart);

        Dictionary<int, string> sharedStringCache = new Dictionary<int, string>();

        int i = 0;
        foreach (var el in workbookPart.SharedStringTablePart.SharedStringTable.ChildElements)
        {
            sharedStringCache.Add(i++, el.InnerText);
        }

        while (reader.Read())
        {
            if(reader.ElementType == typeof(Row))
            {
                reader.ReadFirstChild();

                List<object> cells = new List<object>();

                do
                {
                    if (reader.ElementType == typeof(Cell))
                    {
                        Cell c = (Cell)reader.LoadCurrentElement();

                        if (c == null || c.DataType == null || !c.DataType.HasValue)
                            continue;

                        object value;

                        switch(c.DataType.Value)
                        {
                            case CellValues.Boolean:
                                value = bool.Parse(c.CellValue.InnerText);
                                break;
                            case CellValues.Date:
                                value = DateTime.Parse(c.CellValue.InnerText);
                                break;
                            case CellValues.Number:
                                value = double.Parse(c.CellValue.InnerText);
                                break;
                            case CellValues.InlineString:
                            case CellValues.String:
                                value = c.CellValue.InnerText;
                                break;
                            case CellValues.SharedString:
                                value = sharedStringCache[int.Parse(c.CellValue.InnerText)];
                                break;
                            default:
                                continue;
                        }

                        if (value != null)
                            cells.Add(value);
                    }

                } while (reader.ReadNextSibling());

                if (cells.Any())
                    rows.Add(cells);
            }
        }
    }

    return rows;
}

我在Windows 10 64位上的一台三年前的笔记本电脑上运行该程序,该笔记本电脑具有SSD驱动器,8GB RAM和Intel Core i7-4710 CPU @ 2.50GHz(两个内核)。

请注意,尽管将整个文件作为字符串打开并解析所需的时间不到30秒,但在使用对象时,如上次编辑的示例所示,使用蹩脚的笔记本电脑的时间长达近50秒。使用Linux,您可能会在服务器中接近30秒。

诀窍是使用SAX方法,如下所述:

https://msdn.microsoft.com/en-us/library/office/gg575571.aspx