Python读取Excel文件sheet名性能优化

2020-07-14 14:45:46 浏览数 (1)

原始版本

直接使用pandas读取整个Excel文件,再从中取列名。这种场景对于小的Excel文件还适用,但数据量上升到10M 时,取个sheet name26s之久。几乎无法忍受。

代码语言:javascript复制
data = pandas.ExcelFile(file_url)
names = data.sheet_names

优化

查阅资料可知.xlsx文件是一个压缩格式的文件,可以直接通过zipfile读到sheet name等相关信息。所以写如下函数直接取sheet name

代码语言:javascript复制
def get_sheet_details(file_path):
    sheets = []
    file_name = os.path.splitext(os.path.split(file_path)[-1])[0]
    # 用文件名创建一个临时目录
    directory_to_extract_to = file_name
    os.mkdir(directory_to_extract_to)

    # 提取xlsx文件,因为它只是一个zip文件
    zip_ref = zipfile.ZipFile(file_path, 'r')
    zip_ref.extractall(directory_to_extract_to)
    zip_ref.close()

    # 建立一个临时的workbook文件
    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)
        # 多个sheet
        if isinstance(dictionary['workbook']['sheets']['sheet'], list):
            for sheet in dictionary['workbook']['sheets']['sheet']:
                # 有些版本的sheet是@name有些是@sheetId
                if sheet["@name"]:
                    meta_sheet = sheet["@name"]
                else:
                    meta_sheet = sheet["@sheetId"]
                sheets.append(meta_sheet)
        # 单个sheet
        else:
            sheet_dict = dictionary['workbook']['sheets']['sheet']
            if sheet_dict["@name"]:
                sheets.append(sheet_dict["@name"])
            else:
                sheets.append(sheet_dict["@sheetId"])

    shutil.rmtree(directory_to_extract_to)
    f.close()
    return sheets

使用该种方法,读14M的文件仅需0.04s。(数据都没加载,当然和文件大小无关啦)

一个问题

该函数只能针对.xlsx文件进行解析,而低版本的.xls文件就直接报错了,因为.xls是一个二进制文件而不是压缩文件。所以要以另一种方式去解析sheet name。经过查阅相关资料,发现xlrd.open_workbookon_demand=True针对低版本的Excel文件可以只取列名而不加载数据。

代码语言:javascript复制
if file_url[-3:] == 'xls':
    names = xlrd.open_workbook(file_url, on_demand=True).sheet_names()
else:
    names = get_sheet_details(file_url)

0 人点赞