57

我目前正在使用 pandas 读取 Excel 文件并将其工作表名称呈现给用户,因此他可以选择他想使用的工作表。问题是文件非常大(70 列 x 65k 行),在笔记本上加载最多需要 14 秒(CSV 文件中的相同数据需要 3 秒)。

我在熊猫中的代码是这样的:

xls = pandas.ExcelFile(path)
sheets = xls.sheet_names

我之前尝试过 xlrd,但得到了类似的结果。这是我的 xlrd 代码:

xls = xlrd.open_workbook(path)
sheets = xls.sheet_names

那么,任何人都可以提出一种比读取整个文件更快的方法来从 Excel 文件中检索工作表名称吗?

4

6 回答 6

75

您可以使用xlrd库并使用“on_demand=True”标志打开工作簿,这样就不会自动加载工作表。

比您可以以类似于 pandas 的方式检索工作表名称:

import xlrd
xls = xlrd.open_workbook(r'<path_to_your_excel_file>', on_demand=True)
print xls.sheet_names() # <- remeber: xlrd sheet_names is a function, not a property
于 2012-09-03T15:12:35.257 回答
15

我已经尝试过 xlrd、pandas、openpyxl 和其他此类库,随着文件大小在读取整个文件时增加,它们似乎都需要指数级时间。上面提到的其他使用“on_demand”的解决方案对我不起作用。以下函数适用于 xlsx 文件。

def get_sheet_details(file_path):
    sheets = []
    file_name = os.path.splitext(os.path.split(file_path)[-1])[0]
    # Make a temporary directory with the file name
    directory_to_extract_to = os.path.join(settings.MEDIA_ROOT, file_name)
    os.mkdir(directory_to_extract_to)

    # Extract the xlsx file as it is just a zip file
    zip_ref = zipfile.ZipFile(file_path, 'r')
    zip_ref.extractall(directory_to_extract_to)
    zip_ref.close()

    # Open the workbook.xml which is very light and only has meta data, get sheets from it
    path_to_workbook = os.path.join(directory_to_extract_to, 'xl', 'workbook.xml')
    with open(path_to_workbook, 'r') as f:
        xml = f.read()
        dictionary = xmltodict.parse(xml)
        for sheet in dictionary['workbook']['sheets']['sheet']:
            sheet_details = {
                'id': sheet['sheetId'], # can be @sheetId for some versions
                'name': sheet['name'] # can be @name
            }
            sheets.append(sheet_details)

    # Delete the extracted files directory
    shutil.rmtree(directory_to_extract_to)
    return sheets

由于所有 xlsx 基本上都是压缩文件,因此我们直接从工作簿中提取底层 xml 数据并读取工作表名称,与库函数相比,这只需几分之一秒。

基准测试:(在 4 张 6mb xlsx 文件上)
Pandas,xlrd: 12 秒
openpyxl: 24 秒
建议方法: 0.4 秒

于 2019-05-27T05:37:42.277 回答
9

根据我对标准/流行库的研究,截至2020 年尚未实现/xlsxxls您可以为xlsb. 无论哪种方式,这些解决方案都应该为您带来巨大的性能改进。对于xls, xlsx, xlsb.

下面以 ~10Mb文件为基准xlsxxlsb

xlsx, xls

from openpyxl import load_workbook

def get_sheetnames_xlsx(filepath):
    wb = load_workbook(filepath, read_only=True, keep_links=False)
    return wb.sheetnames

基准测试: ~ 14 倍速度提升

# get_sheetnames_xlsx vs pd.read_excel
225 ms ± 6.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.25 s ± 140 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

xlsb

from pyxlsb import open_workbook

def get_sheetnames_xlsb(filepath):
  with open_workbook(filepath) as wb:
     return wb.sheets

基准测试: ~ 56 倍速度提升

# get_sheetnames_xlsb vs pd.read_excel
96.4 ms ± 1.61 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
5.36 s ± 162 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

笔记:

于 2020-11-09T21:25:57.977 回答
2

通过将@Dhwanil shah 的答案与此处的答案结合起来,我编写的代码也与只有一张纸的 xlsx 文件兼容:

def get_sheet_ids(file_path):
sheet_names = []
with zipfile.ZipFile(file_path, 'r') as zip_ref:
    xml = zip_ref.open(r'xl/workbook.xml').read()
    dictionary = xmltodict.parse(xml)

    if not isinstance(dictionary['workbook']['sheets']['sheet'], list):
        sheet_names.append(dictionary['workbook']['sheets']['sheet']['@name'])
    else:
        for sheet in dictionary['workbook']['sheets']['sheet']:
            sheet_names.append(sheet['@name'])
return sheet_names
于 2020-03-02T15:14:48.043 回答
1

传递了完整 pathlib 路径文件名的 Python 代码适配(例如,('c:\xml\file.xlsx'))。来自Dhwanil shah的回答,没有用于创建临时目录的 Django 方法。

import xmltodict
import shutil
import zipfile


def get_sheet_details(filename):
    sheets = []
    # Make a temporary directory with the file name
    directory_to_extract_to = (filename.with_suffix(''))
    directory_to_extract_to.mkdir(parents=True, exist_ok=True)
    # Extract the xlsx file as it is just a zip file
    zip_ref = zipfile.ZipFile(filename, 'r')
    zip_ref.extractall(directory_to_extract_to)
    zip_ref.close()
    # Open the workbook.xml which is very light and only has meta data, get sheets from it
    path_to_workbook = directory_to_extract_to / 'xl' / 'workbook.xml'
    with open(path_to_workbook, 'r') as f:
        xml = f.read()
        dictionary = xmltodict.parse(xml)
        for sheet in dictionary['workbook']['sheets']['sheet']:
            sheet_details = {
                'id': sheet['@sheetId'],  # can be sheetId for some versions
                'name': sheet['@name']  # can be name
            }
            sheets.append(sheet_details)
    # Delete the extracted files directory
    shutil.rmtree(directory_to_extract_to)
    return sheets
于 2020-08-21T17:28:57.017 回答
-3

你也可以使用

data=pd.read_excel('demanddata.xlsx',sheet_name='oil&gas')
print(data)   

这里 demanddata 是您的文件名称 oil&gas 是您的工作表名称之一。假设您的工作表中可能有 n 个工作表。只需在 Sheet_name="Name of Your required sheet" 处提供您要获取的工作表名称

于 2019-10-08T18:57:54.497 回答