Python openpyxl批量转换xlsx为csv时数据重复写入问题
需求背景
- 共有24个Excel文件,需要将每个
.xlsx文件的各工作表数据导出为对应的csv文件 - 目前已实现基础数据拷贝逻辑,但生成的csv文件中数据重复写入10次,初步判断问题出在for循环逻辑
- 曾尝试将
writerows()替换为writerow(),但问题未解决,当前正在学习openpyxl读写对象相关用法
原有实现代码
import openpyxl, os, csv from pathlib import Path for excelFile in os.listdir('./excelspreadsheets'): if excelFile.endswith('.xlsx'): # Skip non xlsx files, load the workbook object wb = openpyxl.load_workbook('./excelspreadsheets/' + excelFile) for sheetName in wb.sheetnames: # Loop through every sheet in the workbook sheet = wb[sheetName] sheetTitle = sheet.title # Create the CSV filename from the Excel filename and sheet title p = Path(excelFile) excelFileStemName = p.stem CsvFilename = excelFileStemName + '_' + sheetTitle + '.csv' # Create the csv.writer object for this CSV file print(f'Creating filename {CsvFilename}...') outputFile = open(CsvFilename, 'w', newline='') outputWriter = csv.writer(outputFile) # Create reader object for each excel sheet fileObj = open('./excelspreadsheets/' + excelFile) fileReaderObj = csv.reader(fileObj) # Loop through every row in the excel sheet for rowNum in range(1, sheet.max_row + 1): rowData = [] # append each cell to this list # Loop through each cell in the row for colNum in range(1, sheet.max_column + 1): rowData.append(sheet.values) # write the rowData list to the CSV file. for row in rowData: outputWriter.writerows(row) outputFile.close()
异常现象
- 新生成的csv文件写入的数据内容本身正确,但会重复写入10次,而非仅写入1次
问题原因
- 存在冗余无效代码:使用openpyxl加载工作簿后,额外编写了用csv.reader读取xlsx文件的逻辑,xlsx是二进制格式,csv.reader无法正确解析,这段代码完全不生效可以删除
- 取值逻辑错误:内层列循环中
rowData.append(sheet.values)的写法有误,sheet.values是整个工作表所有行值的生成器对象,不是单个单元格的值,每遍历一列就会往rowData中存入一次全表数据,遍历多少列就重复存多少次,这是数据重复的核心原因 - 写入逻辑冗余:外层行循环结束后,又额外遍历了一次rowData调用writerows,进一步放大了数据重复的问题
修复后代码
import openpyxl, os, csv from pathlib import Path for excelFile in os.listdir('./excelspreadsheets'): if excelFile.endswith('.xlsx'): # 加载工作簿,data_only=True读取单元格计算后的值而非公式 wb = openpyxl.load_workbook('./excelspreadsheets/' + excelFile, data_only=True) for sheetName in wb.sheetnames: sheet = wb[sheetName] # 拼接csv文件名 excelFileStemName = Path(excelFile).stem CsvFilename = f"{excelFileStemName}_{sheet.title}.csv" print(f'Creating filename {CsvFilename}...') # 用上下文管理器操作文件,自动完成关闭操作 with open(CsvFilename, 'w', newline='', encoding='utf-8') as outputFile: outputWriter = csv.writer(outputFile) # 直接遍历sheet.values获取每行数据,无需手动循环行列号 for row in sheet.values: outputWriter.writerow(row)
优化说明
- 删除了无效的csv读取xlsx的冗余逻辑
- 直接遍历
sheet.values获取行数据,避免手动循环行列号时的取值错误 - 写入单行数据使用
writerow(),传入单行值列表即可 - 使用
with上下文管理器管理文件IO,无需手动调用close(),避免资源泄漏 - 加载工作簿时增加
data_only=True参数,直接读取单元格计算后的实际值,而非公式字符串 - 写入文件时指定
encoding='utf-8',避免中文乱码问题
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

