# -*- coding: utf-8 -*- """ =============================================================== Python模块:Python操作excel(.xlsx)封装类MyPyXlsToXlsx、myPyXwBook和myPyXwSheet Date:2022年02月07日 我的博客:https://datutu.blog.csdn.net/ =============================================================== """ import re import xlwings as xw from openpyxl.utils import get_column_letter import os import os.path class MyPyXlsToXlsx: """ 类功能: Python使用xlwings操作将xls文件转换为xlsx文件格式类 """ def __init__(self, strOpenFilePath: str): xlsFilePath = strOpenFilePath # 文件存在就加载,不存在就创建工作簿。 if os.path.exists(xlsFilePath): # 文件存在就加载,加载失败就报错。 try: app = xw.App(visible=False, add_book=False) app.display_alerts = False # 关闭一些提示信息,可以加快运行速度。 默认为 True。 app.screen_updating = False # 更新显示工作表的内容。默认为 True。关闭它也可以提升运行速度。 workbook = app.books.open(xlsFilePath) # 打开现有excel workbook.api.SaveAs(xlsFilePath + "x", FileFormat=51) # 参数 51 为xlsx格式;56为 Excel 97-2003的xls版本 app.kill() # 使用kill()关闭进程 os.remove(xlsFilePath) # 删除老的xls文件 except IOError: print("加载xls文件失败!请检查!") else: print("已成功将xls文件转换为xlsx文件!!!\n") else: print("加载的xls文件不存在!请检查!") class myPyXwBook: """ 类功能: Python使用xlwings操作excel(.xlsx)封装类myPyXwBook """ def __init__(self, strOpenFilePath: str): """ :function: 初始化 :param strOpenFilePath: 打开的文件绝对路径 """ self.strFilePath = strOpenFilePath self.app = None # 工作簿对象 self.workbook = None # 文件存在就加载,不存在就创建工作簿。 if os.path.exists(self.strFilePath): # 文件存在就加载,加载失败就报错。 try: self.app = xw.App(visible=False, add_book=False) self.app.display_alerts = False # 关闭一些提示信息,可以加快运行速度。 默认为 True。 self.app.screen_updating = False # 更新显示工作表的内容。默认为 True。关闭它也可以提升运行速度。 self.workbook = self.app.books.open(self.strFilePath) except IOError: print("加载excel文件失败!请检查!") else: print("已成功加载excel文件(.xlsx)文件!!!\n") else: print("加载excel文件不存在!自动创建文件!") self.app = xw.App(visible=False, add_book=False) self.app.display_alerts = False # 关闭一些提示信息,可以加快运行速度。 默认为 True。 self.app.screen_updating = False # 更新显示工作表的内容。默认为 True。关闭它也可以提升运行速度。 self.workbook = self.app.books.add() # 创建工作簿 def openWorkSheet(self, strSheetName: str): """ :function: 打开工作表功能 :param strSheetName: 要打开的工作表名称 :return: 返回打开的工作表Worksheet对象 """ worksheet = None # 工作表对象 listSheetNames = [] for i in range(0, len(self.workbook.sheets)): listSheetNames.append(self.workbook.sheets[i].name) if strSheetName in listSheetNames: worksheet = self.workbook.sheets[strSheetName] else: print("表单名称在当前excel文件中不存在,请检查表单名称!") return worksheet def addSheet(self, strSheetName: str): """ :function: 新建或添加工作表 :param strSheetName: 工作表名称 """ self.workbook.sheets.add(strSheetName) def deleteSheet(self, strSheetName: str): """ :function: 删除工作表 :param strSheetName: 工作表名称 """ if strSheetName in self.getAllSheetNames(): self.workbook.sheets[strSheetName].delete() else: print("表单名称在当前excel文件中不存在,请检查表单名称!") def getAllSheetNames(self): """ :function: 获取一个工作簿所有工作表名称 """ listSheetNames = [] for i in range(0, len(self.workbook.sheets)): listSheetNames.append(self.workbook.sheets[i].name) return listSheetNames def getActiveSheet(self): """ :function: 获取当前活跃的sheet """ return self.workbook.sheets.active def saveWorkBookData(self): """ :function: 保存工作簿数据 """ self.workbook.save(self.strFilePath) def saveAsWorkBookData(self, strNewFilePath: str): """ :function: 另存为工作簿数据 :param strNewFilePath: 新的工作簿名称 """ self.workbook.save(strNewFilePath) def closeWorkBook(self): """ :function: 关闭工作簿 """ # 关闭此工作簿 self.workbook.close() # 关闭app self.app.quit() class myPyXwSheet: """ 类功能: Python使用xlwings操作excel(.xlsx)工作表封装类myPyXwSheet """ def __init__(self, worksheet): # 工作表对象 self.worksheet = worksheet def insertRows(self, strRowsRange): """ :function: 在strRowRange范围上方插入多行或一行 :param strRowsRange: 例, 在第3行上方插入1行,即'3' 在第3行和第4行上方插入2行,即'3:4' """ self.worksheet.api.Rows(strRowsRange).Insert() def deleteRows(self, strCellsRange: str): """ :function: 删除多行或一行 :param strCellsRange: 例, 删除第4行和第5行,即'4:5' 删除第4行,即'4' """ self.worksheet.range(strCellsRange).api.EntireRow.Delete() def insertCols(self, strColsRange: str): """ :function: 在strColsRange范围处(左侧)插入多列或一列 :param strColsRange: 例, 在第C列处插入1列,即'C' 在第C列和第D列处插入2列,即'C:D' """ self.worksheet.api.Columns(strColsRange).Insert() def deleteCols(self, strColsRange): """ :function: 删除多列或一列 :param strColsRange: 单元格范围,例,'C:D'或'C' """ self.worksheet.range(strColsRange).api.EntireColumn.Delete() def getSheetName(self): """ :function: 获取工作表名称 """ return self.worksheet.name def getMaxRows(self): """ :function: 获取工作表最大行数 """ return self.worksheet.used_range.last_cell.row def getUsedRangeData(self): """ :function: 获取工作表已使用区域的全部数据 :备注:返回的是二维列表,例,[[1,2],[3,6] """ return self.worksheet.used_range.value def getMaxColumns(self): """ :function: 获取工作表最大列数 """ return self.worksheet.used_range.last_cell.column def renameSheet(self, strNewSheetName: str): """ :function: 重命名工作表 :param strNewSheetName: 新的工作表名称 """ self.worksheet.name = strNewSheetName def clearSheetContentsAndFormat(self): """ :function: 清空表中所有内容和格式 """ self.worksheet.clear() def clearSheetContents(self): """ :function: 清除工作表的内容,但保留格式 """ self.worksheet.clear_contents() def setCellFormula(self, strCellRange: str, strFormat: str): """ :function: 设置单元格公式 :param strCellRange: 单元格范围,例,‘C6’ :param strFormat: 单元格数字格式,例,'=SUM(B6:B7)' """ self.worksheet[strCellRange].formula = strFormat def getCellFormula(self, strCellRange: str): """ :function: 获取单元格公式 :param strCellRange: 单元格范围,例,‘C6’ """ return self.worksheet[strCellRange].formula_array def setCellNumberFormat(self, strCellRange: str, strNumberFormat: str): """ :function: 设置单元格数字格式 :param strCellRange: 单元格范围,例,‘C6’ :param strNumberFormat: 单元格数字格式,例,'"¥"#,##0.00;-"¥"#,##0.00' 或人民币大写:'[DBNum2][$RMB]G/通用格式;[红色][DBNum2][$RMB]G/通用格式' """ self.worksheet[strCellRange].number_format = strNumberFormat def setRowHeight(self, nRowIndex: int, valRowHeight): """ :function: 设置行高 :param nRowIndex: 行号,取值1,2...整数 :param valRowHeight: 行高度值,0~409之间的整数或浮点数 :return: 设置成功,返回True;否则反 """ # 类型检测 if type(nRowIndex) is not int: print("nRowNumber 数据类型错误!请确认为整数类型") return False if type(valRowHeight) is not int and type(valRowHeight) is not float: print("cur_num 数据类型错误!请确认为整数类型,或者为浮点数类型!") return False # 数字是否出范围 if 0 <= valRowHeight <= 409: self.worksheet.range('A' + str(nRowIndex)).row_height = valRowHeight return True else: print("行高度值,超出了目前最大行高度!") return False def setColumnWidth(self, strColumnIndex: str, valColumnWidth): """ :function: 设置列宽 :param strColumnIndex: 列索引,取值整数1,2...或者'A','B'... :param valColumnWidth: 列宽度值,0~255之间的整数或浮点数 :return: 设置成功,返回True;否则反 """ # 数字检测 if type(strColumnIndex) is int: try: strColumnIndex = get_column_letter(strColumnIndex) # 列号转列字母 except ValueError: print("ColumnIndex参数非法!请确认是输入数据为列索引字符串!") return False if type(valColumnWidth) is not int and type(valColumnWidth) is not float: print("valColumnWidth 数据类型错误!请确认为整数类型,或者为浮点数类型!") return False # 数字是否出范围 if 0 <= valColumnWidth <= 255: self.worksheet.range(strColumnIndex + '1').column_width = valColumnWidth return True else: print("列宽度值,超出了目前最大列宽度!") return False def setRowsHeight(self, strCellsRange: str, valRowHeight): """ :function: 设置多行行高 :param strCellsRange: 例,单元格'A2:D5'或'A2' :param valRowHeight: 行高度值,0~409之间的整数或浮点数 :return: 设置成功,返回True;否则反 """ if type(valRowHeight) is not int and type(valRowHeight) is not float: print("cur_num 数据类型错误!请确认为整数类型,或者为浮点数类型!") return False # 数字是否出范围 if 0 <= valRowHeight <= 409: self.worksheet.range(strCellsRange).row_height = valRowHeight return True else: print("行高度值,超出了目前最大行高度!") return False def setColumnsWidth(self, strCellsRange: str, valColumnWidth): """ :function: 设置多列列宽 :param strCellsRange: 例,单元格'A2:D5'或'A2' :param valColumnWidth: 列宽度值,0~255之间的整数或浮点数 :return: 设置成功,返回True;否则反 """ if type(valColumnWidth) is not int and type(valColumnWidth) is not float: print("valColumnWidth 数据类型错误!请确认为整数类型,或者为浮点数类型!") return False # 数字是否出范围 if 0 <= valColumnWidth <= 255: self.worksheet.range(strCellsRange).column_width = valColumnWidth return True else: print("列宽度值,超出了目前最大列宽度!") return False def getCellRowIndex(self, strCellRange: str): """ :function: 获取单元格的行标 :param strCellRange: 例,单元格'A2' :return: 返回单元格的行标 """ return self.worksheet.range(strCellRange).row def getCellColIndex(self, strCellRange: str): """ :function: 获取单元格的列标 :param strCellRange: 例,单元格'A2' :return: 返回单元格的列标 """ return self.worksheet.range(strCellRange).column def putDataByCell(self, strCellRange: str, Value): """ :function: 写入一个单元格数据功能 :param strCellRange: 例,单元格'A2' :param Value: 写入指定单元格的数值 """ self.worksheet.range(strCellRange).value = Value def getDataByCell(self, strCellRange: str): """ :function: 读取一个单元格数据功能 :param strCellRange: 例,单元格'A2' :备注:返回的数值默认是浮点数 """ return self.worksheet.range(strCellRange).value def putDataByRowOrCol(self, strCellsRange: str, listData: list): """ :function:写入一行或一列数据 :param strCellsRange: 例,单元格范围,一行'A2:D2'或一列'A2:A4'或单元格'A2' :param listData: 一维数据列表,[] """ index = 0 for row in self.worksheet[strCellsRange]: for cell in row: if index >= len(listData): print("一维列表下表超出范围!") else: cell.value = listData[index] index += 1 def getDataByRowOrCol(self, strCellsRange: str) -> list: """ :function:读取一行或一列数据 :param strCellsRange: 例,单元格范围,一行'A2:D2'或一列'A2:A4'或单元格'A2' :return:一维列表[],返回的数值默认是浮点数 """ return self.worksheet.range(strCellsRange).value def putDataByRow(self, strCellRange: str, listData: list): """ :function:以第一个单元格为起点,写入一行数据 :param strCellRange: 例,单元格'A2' :param listData: 一维数据列表,[] :备注: # 将列表[1,2,3]储存在A1:C1中 self.worksheet.range('A1').value=[1,2,3] # 等同于 self.worksheet.range('A1:C1').value = [1,2,3] """ self.worksheet.range(strCellRange).value = listData def putDataByCol(self, strCellRange: str, listData: list): """ :function:以第一个单元格为起点,写入一列数据 :param strCellRange: 例,单元格'A2' :param listData: 一维数据列表,[] :备注: # 将列表[1,2,3]储存在A1:A3中 self.worksheet.range('A1').options(transpose=True).value=[1,2,3] """ self.worksheet.range(strCellRange).options(transpose=True).value = listData def putDataByRows(self, strCellsRange: str, listData: list): """ :function:以第一个单元格为起点,多行输入就要用二维列表 :param strCellsRange: 例,单元格'A2' :param listData: 二维数据列表,例,[[1,2],[3,4]] :备注: # 将2x2表格,即二维数组,储存在A1:B2中,如第一行1,2,第二行3,4 self.worksheet.range('A1').options(expand='table').value=[[1,2],[3,4]] """ self.worksheet.range(strCellsRange).options(expand='table').value = listData def getDataByRows(self, strCellsRange: str) -> list: """ :function:读取多行数据就要用二维列表 :param strCellsRange: 例,单元格范围,'A2:C6' :return listData: 二维数据列表,例,[[1,2],[3,4]] :备注:返回的数值默认是浮点数 """ return self.worksheet.range(strCellsRange).value def getCellRowHeight(self, nRowIndex: int): """ :function:获取单元格行高度 :param nRowIndex: 例,1, 2, 3,... :return: 返回单元格行高度 """ return self.worksheet.range('A' + str(nRowIndex)).row_height def getCellColWidth(self, strColumnIndex: str): """ :function:获取单元格列宽度 :param strColumnIndex: 例,'A','B',... :return: 返回单元格列宽度 """ fColWidth = self.worksheet.range(strColumnIndex + '1').column_width # 浮点数保留2位小数 fNewColWidth = round(fColWidth, 2) return fNewColWidth def setRowsAutofit(self, strCellsRange: str): """ :function:单元格范围的所有行宽度自适应 :param strCellsRange: 例,单元格范围,'A2:C6' """ # 所有行宽度自适应 self.worksheet.range(strCellsRange).rows.autofit() def setColAutofit(self, strCellsRange: str): """ :function:单元格范围的所有列宽度自适应 :param strCellsRange: 例,单元格范围,'A2:C6' """ # 所有行宽度自适应 self.worksheet.range(strCellsRange).columns.autofit() def setAutofit(self, strCellsRange: str): """ :function:单元格范围的所有行和列的宽度自适应 :param strCellsRange: 例,单元格范围,'A2:C6' """ # 所有行宽度自适应 self.worksheet.range(strCellsRange).autofit() def getRangeRowsCount(self, strCellsRange: str): """ :function:获取单元格范围range的总行数 :param strCellsRange: 例,单元格范围,'A2:C6' :return : 单元格范围range的总行数 """ return self.worksheet.range(strCellsRange).rows.count def getRangeColsCount(self, strCellsRange: str): """ :function:获取单元格范围range的总列数 :param strCellsRange: 例,单元格范围,'A2:C6' :return : 单元格范围range的总列数 """ return self.worksheet.range(strCellsRange).columns.count def getRangeRows(self, strCellsRange: str) -> list: """ :function:获取单元格范围range的行对象列表 :param strCellsRange: 例,单元格范围,'A2:C6' :return : 单元格范围range的行对象列表 """ # 返回第一行数据列表 # return self.worksheet.range(strCellsRange).rows[0].value # 返回单元格范围range的行对象列表 return self.worksheet.range(strCellsRange).rows def copyRange(self, strSourceCellsRange: str): """ :function:同一个工作表或不同工作表,把一个区域拷贝到剪贴板 :param strSourceCellsRange: 例,源单元格范围,'A1:B3' """ # 参数:destination 设置目标区域,如果省略,rng区域会被拷贝到剪贴板上 self.worksheet.range(strSourceCellsRange).copy(destination=None) def pasteRange(self, strDestCellsRange: str, paste=None, operation=None, skip_blanks=False, transpose=False): """ :function:同一个工作表或不同工作表,把剪贴板拷贝到目的区域 :param strDestCellsRange: 例,目的单元格范围,'D5'或'D5:E7' :param paste: 参数: 【paste】 all_merging_conditional_formats(将粘贴所有内容,并且将合并条件格式) all(粘贴全部内容) all_except_borders(粘贴除边框外的全部内容) all_using_source_theme(使用源主题粘贴全部内容) column_widths(粘贴复制的列宽) comments(粘贴批注) formats(粘贴复制的源格式) formulas(粘贴公式) formulas_and_number_formats(粘贴公式和数字格式) validation(粘贴有效性) values(粘贴值) values_and_number_formats(粘贴值和数字格式) :param operation: 参数: 【operation】 add(加) divide(除) multiply(乘) subtract(减) :param skip_blanks: 参数: 【skip_blanks】 (bool, default False),设为 True 时忽略空白单元格 :param transpose: 参数: 【transpose】 (bool, default False),设为 True 时对行列转置 """ # 将剪贴板里内容粘贴到指定区域 self.worksheet.range(strDestCellsRange).paste(paste=paste, operation=operation, skip_blanks=skip_blanks, transpose=transpose) def copyPasteRange(self, strSourceCellsRange: str, strDestCellsRange: str): """ :function:同一个工作表内,把一个区域复制粘贴到目的区域 :param strSourceCellsRange: 例,源单元格范围,'A1:B3' :param strDestCellsRange: 例,目的单元格范围,'D5'或'D5:E7' """ '''同个表格复制、粘贴''' # 复制 A1 到 B3 之间单元格的值,粘贴到'D5'中 self.worksheet.range(strSourceCellsRange).api.Copy(self.worksheet.range(strDestCellsRange).api) def setCellMerge(self, strCellsRange: str): """ :function: 合并单元格 :param strCellsRange: 例,单元格范围,'A1:D1' """ self.worksheet.range(strCellsRange).merge(across=False) def setCellUnMerge(self, strCellsRange: str): """ :function: 拆分单元格 :param strCellsRange: 例,单元格范围,'A1:D1' """ self.worksheet.range(strCellsRange).unmerge() def setFontStyleByCells(self, strCellsRange: str, name="宋体", size=11, bold=False, italic=False, color=1): """ :function:设置一个或多个单元格的字体样式风格 配置字体格式为:样式(宋体)、尺寸(11)、粗体(flase)、斜体(flase)、颜色(黑色) 这里可以根据自己需求修改 :param strCellsRange: 例,单元格范围'A29:F39'或单元格'A2' :param name: 字体名称 :param size: 字体大小点数 :param bold: True表示粗体 :param italic: True表示斜体 :param color: 字体颜色 ===字体颜色索引=== 无色 = -4142,自动 = -4105,黑色 = 1, 白色 = 2 , 红色 = 3,鲜绿 = 4, 蓝色 = 5 ,黄色 = 6,粉红 = 7, 青绿 = 8 ,深红 = 9,绿色 = 10, 深蓝 = 11,深黄 = 12 ,紫罗兰 = 13, 青色 = 14,灰色25 = 15,褐色 = 53, 橄榄 = 52,深绿 = 51,深青 = 49, 靛蓝 = 55,灰色80 = 56,橙色 = 46, 蓝灰 = 47,灰色50 = 16,浅橙色 = 45, 酸橙色 = 43,海绿 = 50, 水绿色 = 42, 浅蓝 = 41, 灰色40 = 48,金色 = 44, 天蓝 = 33,梅红 = 54,玫瑰红 = 38, 茶色 = 40,浅黄 = 36,浅绿 = 35, 浅青绿 = 34,淡蓝 = 37,淡紫 = 39, """ cellRange = self.worksheet.range(strCellsRange) cellRange.api.Font.Name = name # 设置字体名称 cellRange.api.Font.Size = size # 设置字体大小 cellRange.api.Font.Bold = bold # 设置字体是否加粗 cellRange.api.Font.Italic = italic # 设置字体是否斜体 cellRange.api.Font.ColorIndex = color # 设置字体颜色 @staticmethod def strHorizontalAlignment_to_int(strHorizontalAlignment: str): """ :function:水平对齐方式字符串转int :param strHorizontalAlignment: 水平对齐方式字符串,'left'、'center'、'right' """ numbers = { 'left': -4131, 'center': -4108, 'right': -4152 } return numbers.get(strHorizontalAlignment, None) @staticmethod def strVerticalAlignment_to_int(strVerticalAlignment: str): """ :function:垂直对齐方式字符串转int :param strVerticalAlignment: 垂直对齐方式字符串,'top'、'center'、'bottom'、'wordwrap' """ numbers = { 'top': -4160, 'center': -4108, 'bottom': -4107, 'wordwrap': -4130 } return numbers.get(strVerticalAlignment, None) def setAlignmentStyleByCells(self, strCellsRange: str, horizontal='center', vertical='center'): """ :function:设置一个或多个单元格的对齐方式 :param strCellsRange: 例,单元格范围'A29:F39'或单元格'A2' :param horizontal: 水平对齐方式,'left'、'center'、'right' :param vertical: 垂直对齐方式,'top'、'center'、'bottom'、'wordwrap' """ cellRange = self.worksheet.range(strCellsRange) # -4108 水平居中。 -4131 靠左,-4152 靠右。 cellRange.api.HorizontalAlignment = self.strHorizontalAlignment_to_int(horizontal) # -4108 垂直居中(默认)。 -4160 靠上,-4107 靠下, -4130 自动换行对齐。 cellRange.api.VerticalAlignment = self.strVerticalAlignment_to_int(vertical) def setBorderStyleByCell(self, strCellsRange: str, nBorderLineStyle: int = 1, nBorderWeight: int = 2): """ :function:设置一个或多个单元格的边框样式 :param strCellsRange: 例,单元格范围'A29:F39'或单元格'A2' :param nBorderLineStyle: 【边框线型】,例,直线:1;虚线:2;点划线:4;双点划线:5 :param nBorderWeight: 【边框粗细】,例,默认值2 """ cellRange = self.worksheet.range(strCellsRange) # Borders(7) 左边框 cellRange.api.Borders(7).LineStyle = nBorderLineStyle # 设置边框线型 cellRange.api.Borders(7).Weight = nBorderWeight # 设置边框粗细。 # Borders(8) 顶部框 cellRange.api.Borders(8).LineStyle = nBorderLineStyle cellRange.api.Borders(8).Weight = nBorderWeight # Borders(9) 底部边框 cellRange.api.Borders(9).LineStyle = nBorderLineStyle cellRange.api.Borders(9).Weight = nBorderWeight # Borders(10) 右边框 cellRange.api.Borders(10).LineStyle = nBorderLineStyle cellRange.api.Borders(10).Weight = nBorderWeight """如果是一个区域的单元格,内部边框设置如下""" # Borders(11) 内部垂直边线 cellRange.api.Borders(11).LineStyle = nBorderLineStyle cellRange.api.Borders(11).Weight = nBorderWeight # Borders(12) 内部水平边线 cellRange.api.Borders(12).LineStyle = nBorderLineStyle cellRange.api.Borders(12).Weight = nBorderWeight """ =============================================================== 主函数 =============================================================== """ if __name__ == '__main__': # excel文件绝对路径 xlsxFilePath = os.path.join(os.getcwd() + "\\" + "someip.xlsx") # 创建工作簿对象 myXwBook = myPyXwBook(xlsxFilePath) # 创建工作表对象 myXwSheet1 = myPyXwSheet(myXwBook.openWorkSheet("ServiceInterfaces")) # 写入数据 # myXwSheet1.putDataByRowOrCol('A1:A4', [1, 2, 3, 4]) # 读数据 readData = myXwSheet1.getDataByCell('A2:C2') print(readData) # 保存工作簿数据 myXwBook.saveWorkBookData() # 关闭工作簿 myXwBook.closeWorkBook()