| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- """
- Excel 工具类
- 该文件提供 Excel 解析功能,支持:
- - 解析 .xlsx 和 .xls 格式的 Excel 文件
- - 将 Excel 数据转换为 List[Dict[str, Any]] 格式
- - 支持指定工作表
- - 支持自定义表头行
- """
- from typing import List, Dict, Any, Optional
- import os
- try:
- from openpyxl import load_workbook
- from openpyxl.worksheet.worksheet import Worksheet
- except ImportError:
- raise ImportError("openpyxl 库未安装,请使用 pip install openpyxl 安装")
- try:
- import xlrd
- from xlrd.sheet import Sheet
- except ImportError:
- raise ImportError("xlrd 库未安装,请使用 pip install xlrd 安装")
- class ExcelUtil:
- """
- Excel 工具类,用于解析 Excel 文件
- """
-
- @staticmethod
- def _parse_xlsx(file_path: str, sheet_name: Optional[str] = None, header_row: int = 0) -> List[Dict[str, Any]]:
- """
- 解析 .xlsx 格式的 Excel 文件
-
- Args:
- file_path: Excel 文件路径
- sheet_name: 工作表名称,None 表示使用第一个工作表
- header_row: 表头所在行索引,默认第 0 行
-
- Returns:
- List[Dict[str, Any]]: 解析后的 Excel 数据
- """
- # 加载工作簿
- workbook = load_workbook(filename=file_path, read_only=True)
-
- # 获取工作表
- if sheet_name:
- sheet: Worksheet = workbook[sheet_name]
- else:
- sheet: Worksheet = workbook.active
-
- # 获取所有行数据
- rows = list(sheet.iter_rows(values_only=True))
-
- # 检查数据是否为空
- if not rows:
- return []
-
- # 检查表头行索引是否合法
- if header_row >= len(rows):
- raise ValueError(f"表头行索引 {header_row} 超出数据总行数 {len(rows)}")
-
- # 获取表头
- headers = rows[header_row]
-
- # 检查表头是否为空
- if not headers:
- return []
-
- # 解析数据行
- data: List[Dict[str, Any]] = []
- for row in rows[header_row + 1:]:
- if not row or all(cell is None for cell in row):
- continue
-
- # 创建数据字典
- row_data: Dict[str, Any] = {}
- for i, header in enumerate(headers):
- if i < len(row):
- row_data[header] = row[i]
- else:
- row_data[header] = None
-
- data.append(row_data)
-
- workbook.close()
- return data
-
- @staticmethod
- def _parse_xls(file_path: str, sheet_name: Optional[str] = None, header_row: int = 0) -> List[Dict[str, Any]]:
- """
- 解析 .xls 格式的 Excel 文件
-
- Args:
- file_path: Excel 文件路径
- sheet_name: 工作表名称,None 表示使用第一个工作表
- header_row: 表头所在行索引,默认第 0 行
-
- Returns:
- List[Dict[str, Any]]: 解析后的 Excel 数据
- """
- # 打开工作簿
- workbook = xlrd.open_workbook(file_path)
-
- # 获取工作表
- if sheet_name:
- sheet: Sheet = workbook.sheet_by_name(sheet_name)
- else:
- sheet: Sheet = workbook.sheet_by_index(0)
-
- # 获取所有行数据
- rows = []
- for i in range(sheet.nrows):
- rows.append(sheet.row_values(i))
-
- # 检查数据是否为空
- if not rows:
- return []
-
- # 检查表头行索引是否合法
- if header_row >= len(rows):
- raise ValueError(f"表头行索引 {header_row} 超出数据总行数 {len(rows)}")
-
- # 获取表头
- headers = rows[header_row]
-
- # 检查表头是否为空
- if not headers:
- return []
-
- # 解析数据行
- data: List[Dict[str, Any]] = []
- for row in rows[header_row + 1:]:
- if not row or all(cell == '' or cell is None for cell in row):
- continue
-
- # 创建数据字典
- row_data: Dict[str, Any] = {}
- for i, header in enumerate(headers):
- if i < len(row):
- row_data[header] = row[i]
- else:
- row_data[header] = None
-
- data.append(row_data)
-
- return data
-
- @staticmethod
- def parse_excel(file_path: str, sheet_name: Optional[str] = None, header_row: int = 0) -> List[Dict[str, Any]]:
- """
- 解析 Excel 文件,支持 .xlsx 和 .xls 格式
-
- Args:
- file_path: Excel 文件路径
- sheet_name: 工作表名称,None 表示使用第一个工作表
- header_row: 表头所在行索引,默认第 0 行
-
- Returns:
- List[Dict[str, Any]]: 解析后的 Excel 数据
-
- Raises:
- ValueError: 不支持的文件格式
- FileNotFoundError: 文件不存在
- """
- # 检查文件是否存在
- if not os.path.exists(file_path):
- raise FileNotFoundError(f"文件 {file_path} 不存在")
-
- # 获取文件扩展名
- file_ext = os.path.splitext(file_path)[1].lower()
-
- # 根据文件格式选择解析方法
- if file_ext == '.xlsx':
- return ExcelUtil._parse_xlsx(file_path, sheet_name, header_row)
- elif file_ext == '.xls':
- return ExcelUtil._parse_xls(file_path, sheet_name, header_row)
- else:
- raise ValueError(f"不支持的文件格式 {file_ext},只支持 .xlsx 和 .xls 格式")
-
- @staticmethod
- def get_sheet_names(file_path: str) -> List[str]:
- """
- 获取 Excel 文件中的所有工作表名称
-
- Args:
- file_path: Excel 文件路径
-
- Returns:
- List[str]: 工作表名称列表
-
- Raises:
- ValueError: 不支持的文件格式
- FileNotFoundError: 文件不存在
- """
- # 检查文件是否存在
- if not os.path.exists(file_path):
- raise FileNotFoundError(f"文件 {file_path} 不存在")
-
- # 获取文件扩展名
- file_ext = os.path.splitext(file_path)[1].lower()
-
- # 根据文件格式选择方法
- if file_ext == '.xlsx':
- workbook = load_workbook(filename=file_path, read_only=True)
- sheet_names = workbook.sheetnames
- workbook.close()
- return sheet_names
- elif file_ext == '.xls':
- workbook = xlrd.open_workbook(file_path)
- sheet_names = workbook.sheet_names()
- return sheet_names
- else:
- raise ValueError(f"不支持的文件格式 {file_ext},只支持 .xlsx 和 .xls 格式")
- # 单例模式实例
- excel_util = ExcelUtil()
|