Python 如何在不加载整个文件的情况下从XLS文件中获取图纸名称?

Python 如何在不加载整个文件的情况下从XLS文件中获取图纸名称?,python,excel,pandas,xlrd,Python,Excel,Pandas,Xlrd,我目前正在使用pandas读取Excel文件,并将其工作表名称呈现给用户,以便用户可以选择要使用的工作表。问题是这些文件实际上是70列x 65k行的大文件,在笔记本上加载这些数据需要14秒,而CSV文件中的相同数据需要3秒 我在panda中的代码如下所示: xls = pandas.ExcelFile(path) sheets = xls.sheet_names 我以前尝试过xlrd,但得到了类似的结果。这是我使用xlrd的代码: xls = xlrd.open_workbook(path)

我目前正在使用pandas读取Excel文件,并将其工作表名称呈现给用户,以便用户可以选择要使用的工作表。问题是这些文件实际上是70列x 65k行的大文件,在笔记本上加载这些数据需要14秒,而CSV文件中的相同数据需要3秒

我在panda中的代码如下所示:

xls = pandas.ExcelFile(path)
sheets = xls.sheet_names
我以前尝试过xlrd,但得到了类似的结果。这是我使用xlrd的代码:

xls = xlrd.open_workbook(path)
sheets = xls.sheet_names
那么,有谁能建议一种比读取整个文件更快的从Excel文件检索工作表名称的方法吗?

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

然后,可以使用与以下类似的方式检索图纸名称:

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

我尝试过xlrd、pandas、openpyxl和其他类似的库,所有这些库在读取整个文件时,随着文件大小的增加,似乎都需要指数级的时间。上面提到的其他解决方案,他们使用“随需应变”对我不起作用。以下函数适用于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数据并直接从工作簿读取工作表名称,这与库函数相比只需几秒钟

基准测试:在一个6mb xlsx文件上,共4页 熊猫,xlrd:12秒 openpyxl:24秒 建议的方法:0.4秒

您也可以使用

data=pd.read_excel('demanddata.xlsx',sheet_name='oil&gas')
print(data)   
demanddata是您的文件名
oil&gas是您的工作表名称之一。您的工作表中可能有n张工作表。只需将@Dhwanil shah的答案与我编写的答案相结合,在sheet_name=所需工作表的名称中给出您想要获取的工作表的名称即可。我编写的代码也与只有一张工作表的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

传递了完整pathlib路径文件名的Python代码自适应,例如“c:\xml\file.xlsx”。 在answer中,不使用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

根据我对标准/流行LIB的研究,截至2020年,xlsx/xls尚未实现这一点,但您可以为xlsb实现这一点。无论采用哪种方式,这些解决方案都会大大提高性能。对于xls,xlsx,xlsb

以下是在~10Mb xlsx、xlsb文件上进行的基准测试

xlsx,xls 基准测试:速度提高约14倍

xlsb 基准测试:速度提高约56倍

注:

这是一个很好的资源- xlrd从2020年起不再维护
直接在Excel中打开这样一个文件需要多长时间?@DocBrown如果Excel已经打开Excel Starter 2010,则大约需要4s。xlrd文档说,这仅适用于BIFF>=5.0。它对我不起作用,如果我问xls.biff_版本,它会说0,这似乎很奇怪,不可能?。你知道会发生什么吗?你也可以将xlrd.open_工作簿的结果传递到pandas.ExcelFile,并像以前那样与对象交互:xls=pandas.ExcelFilexlrd.open_workbookpath,on_demand=true这对于工作表名称来说太慢了。对于5MB文件,它花费了11秒。似乎它承载了整个file@rluts我同意,这种方法仍然非常缓慢。有更好的解决方案吗?您需要配置一组Django设置才能使用它。你能告诉我怎么做吗?绕过Django的要求,我也遇到了这样的错误:文件不是zip文件,我的文件是Microsoft Excel 97-2003工作表。xls可能不适用于旧版本的Excel@CoreyLevinson,正如在文章中提到的,这只适用于xlsx文件,因为.xlsx文件使用Office Open XML,这是一种压缩的XML格式。xls文件使用BIFF格式。我还没有遇到xls文件的要求。但如果你能找到一个解压和阅读内部内容的方法,我认为这种方法也会对你有用。此外,无需更改django设置,我只使用media_cdn或BASE_DIR,并在与其相关的位置创建一个temp DIR。您的代码节省了数小时的工作,这些代码有一个问题我必须解决,这基本上是如果Excel只有一个工作表,它会抛出一个错误,我使用这些单行工作表1=字典[“工作簿”]['sheets']['sheet']如果没有安装sheets1,list:sheets1=[sheets1]@piyushmandovra我做了同样的修复,回来这里添加了一条关于它的评论,结果发现你的评论在这里。我建议解释为什么这个方法会比他当前的方法更快,或者在某些情况下显示它更快。一般来说,提供更多的证据这可能是一个很好的答案,但提供更多的依据说明为什么它很好将有助于读者对其进行评估。谢谢@xgoniveittoya。这是一个很好的建议&我会这样做。这不符合OP的要求,即从一本最初未知的工作簿中获取工作表的名称。相反,这是从已知的表格中提取数据。回答得很好,格伦!谢谢
from openpyxl import load_workbook

def get_sheetnames_xlsx(filepath):
    wb = load_workbook(filepath, read_only=True, keep_links=False)
    return wb.sheetnames
# 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)
from pyxlsb import open_workbook

def get_sheetnames_xlsb(filepath):
  with open_workbook(filepath) as wb:
     return wb.sheets
# 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)