多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Python CSV转Excel全攻略:Pandas、Openpyxl、XlsxWriter实战对比

Python CSV转Excel全攻略:Pandas、Openpyxl、XlsxWriter实战对比 1. 项目概述从CSV到Excel的格式转换实战在日常的数据处理工作中我们最常打交道的两种文件格式莫过于CSV和Excel了。CSV文件轻巧、通用是系统间数据交换的“硬通货”而Excel文件则功能强大、展示友好是数据分析、报告呈现的“主舞台”。作为一名经常用Python处理数据的开发者我几乎每天都会遇到需要将CSV文件转换为Excel格式的需求。这听起来简单但实际操作中你会面临格式兼容性、数据完整性、性能瓶颈以及中文编码等一系列“暗礁”。比如一个包含特殊字符或换行符的CSV文件用pandas直接读取可能会报错又或者当你需要将数据导出为老旧的.xls格式以兼容某些遗留系统时会发现常用的库并不直接支持。这个项目标题“python 将 csv转excel (.xls和.xlsx)的几种方式”其核心价值就在于系统性地梳理和解决这些痛点。它不仅仅是调用一个to_excel()函数那么简单而是涵盖了从基础工具选型、不同场景下的最佳实践到高级功能定制和疑难杂症排查的完整知识链。无论你是刚入门Python的数据分析师还是需要维护数据ETL流程的后端工程师掌握这几套方法都能让你在面对格式转换任务时游刃有余。接下来我将结合我多年的实战经验为你拆解几种主流且高效的转换方式并深入探讨它们背后的原理、适用场景以及那些官方文档里不会写的“坑”。2. 核心工具库选型与对比在Python生态中处理CSV转Excel的库不止一个每个都有其独特的定位和优劣。盲目选择一个可能会在后续遇到性能问题或功能限制。因此理解这些工具的核心差异是第一步。2.1 全能选手PandasPandas无疑是数据科学领域的“瑞士军刀”。它并非专为Excel操作而生但其强大的DataFrame数据结构和丰富的I/O接口使得它成为CSV转Excel最流行、最便捷的选择。核心优势接口极其简洁通常只需两行代码read_csv()加to_excel()即可完成转换。数据处理能力强转换前你可以轻松进行数据清洗、过滤、计算等复杂操作转换只是最后一步。格式支持良好通过指定engine参数openpyxl用于.xlsxxlwt用于.xls能较好地支持两种格式。内在原理与局限Pandas的to_excel()方法本质上是一个高级封装器。对于.xlsx它调用openpyxl库在内存中构建工作簿和工作表对于.xls则调用已停止维护的xlwt库。这意味着当处理超大型文件比如几十万行时Pandas需要将整个DataFrame读入内存可能会遇到内存瓶颈。此外它对Excel文件样式的控制能力比较基础如果你想精细设置单元格字体、颜色、边框Pandas就显得力不从心了。2.2 专业制表Openpyxl 与 XlsxWriter当你需要对生成的Excel文件进行像素级控制时openpyxl和XlsxWriter这类专业库就该登场了。Openpyxl专注于读写.xlsx格式。它允许你从零开始创建或修改一个工作簿可以精确到对任意单元格进行样式设置、插入公式、添加图表等。它的API设计更贴近Excel的对象模型工作簿、工作表、单元格。XlsxWriter同样只支持.xlsx但它是一个纯写入库不能读取。其优势在于性能卓越尤其在写入大量数据时和功能非常全面支持更多的图表类型和Excel高级功能。它们与CSV的衔接这两个库本身不直接读取CSV。标准的做法是先用Python内置的csv模块或Pandas将CSV数据读入内存如列表或DataFrame然后通过循环遍历将数据逐个单元格地写入到openpyxl或XlsxWriter创建的工作表中。这个过程给了你最大的灵活性但也意味着你需要编写更多的代码。2.3 遗留格式专家xlwt 与 xlrd如果你的目标格式是古老的.xlsExcel 97-2003那么xlwt写和xlrd读是曾经的标准。不过需要注意的是xlrd在2.0.0版本后已不再支持读取.xlsx文件且整个库生态已基本停止更新。当前实践对于.xls写入Pandas指定enginexlwt仍然是最高效的封装。但如果需要更复杂的.xls格式控制你可能仍需直接使用xlwt。考虑到兼容性除非有强制要求否则建议将输出目标升级为.xlsx。注意直接使用xlwt时需注意其单个工作表最多支持65536行、256列。超出限制会导致数据截断而Pandas在使用xlwt引擎时会自动检查并抛出错误这是一个重要的安全网。2.4 选型决策速查表为了帮你快速决策我整理了以下对比表格特性/需求PandasOpenpyxlXlsxWriter直接使用 xlwt核心优势一站式数据操作与转换读写.xlsx样式控制灵活高性能写入.xlsx功能强大专门写入.xls格式代码简洁度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐大数据处理受内存限制受内存限制性能最优支持常量内存模式行数有限制(65536)样式控制基础精细非常精细基础支持格式.xlsx, .xls.xlsx.xlsx.xls适用场景快速转换、附带数据清洗需要修改现有文件或复杂样式生成大型、带复杂图表报告必须输出.xls旧格式3. 方法一使用Pandas进行快速通用转换这是最快速、最常用的方法适合绝大多数不涉及复杂格式的日常转换任务。3.1 基础转换流程基础操作只需要四步导入库、读取CSV、转换为Excel、保存文件。但每一步都有细节需要注意。import pandas as pd # 1. 读取CSV文件 # 关键参数encoding编码 sep分隔符 header是否将首行作为列名 df pd.read_csv(input.csv, encodingutf-8-sig) # 2. 查看数据非必须但建议 print(df.head()) # 查看前5行 print(df.info()) # 查看数据概览检查数据类型 # 3. 转换为Excel并保存 # 关键参数index是否写入行索引 sheet_name工作表名 df.to_excel(output.xlsx, indexFalse, sheet_nameData) print(转换完成)参数详解与避坑指南encodingutf-8-sig这是处理中文CSV文件的“黄金参数”。utf-8-sig会在文件开头添加BOM字节顺序标记确保Excel打开时能正确识别UTF-8编码避免中文乱码。如果文件是gbk编码则需改为encodinggbk。indexFalse强烈建议设置为False。Pandas的DataFrame自带行索引0,1,2...如果不关闭它会作为第一列写入Excel这通常不是我们想要的原始数据。sep参数默认是逗号但有时CSV会用制表符\tTSV或其他字符分隔。如果读取后所有数据挤在一列首先检查分隔符。3.2 处理.xls格式与大数据分片当需要输出.xls或处理大型文件时需要一些额外操作。输出.xls格式只需在to_excel()中指定引擎即可。由于xlwt不支持.xlsxPandas会自动根据文件后缀选择引擎但显式指定是更佳实践。# 输出为.xls格式 df.to_excel(output.xls, indexFalse, enginexlwt) # 输出为.xlsx格式也可显式指定引擎openpyxl是默认引擎之一 df.to_excel(output.xlsx, indexFalse, engineopenpyxl)处理大型CSV文件如果CSV文件太大无法一次性读入内存可以使用chunksize参数进行分块读取和处理。chunk_size 50000 # 每次处理5万行 chunk_list [] # 用于存储每个块的处理结果如果需整体处理 # 方案A分块读取分别写入同一个Excel文件的不同工作表需借助ExcelWriter with pd.ExcelWriter(large_output.xlsx, engineopenpyxl) as writer: for i, chunk in enumerate(pd.read_csv(large_input.csv, chunksizechunk_size, encodingutf-8-sig)): # 可以对chunk进行一些处理 processed_chunk chunk.dropna() # 例如删除空行 sheet_name fChunk_{i} processed_chunk.to_excel(writer, indexFalse, sheet_namesheet_name) # 方案B分块读取过滤后再合并写入如果内存允许最终合并的数据 # 此方法适用于需要跨块聚合计算的场景实操心得使用pd.ExcelWriter配合with语句是写入多个工作表的正确姿势。它能确保文件被正确关闭和保存即使在写入过程中发生异常。直接在一个循环里多次调用df.to_excel(‘same_file.xlsx‘)会覆盖之前的内容。3.3 常见问题与排查ModuleNotFoundError: No module named ‘openpyxl‘问题Pandas默认可能未安装openpyxl引擎。解决通过pip安装即可。pip install openpyxl。对于.xls则需要pip install xlwt。文件打开报错“发现xxx中的部分内容有问题…”问题这通常是因为数据中包含了Excel无法直接渲染的特殊字符或者单元格内容超长。解决在读取CSV后使用df.replace()清理特殊字符例如df df.replace(r‘[\x00-\x1f\x7f-\x9f]‘, ‘’, regexTrue)移除控制字符。检查是否有字段包含超长的文本超过Excel单元格限制可以考虑截断或换行。日期/时间格式混乱问题CSV中的日期字符串在Excel中变成了数字或格式不对。解决在read_csv时使用parse_dates参数指定需要解析为日期时间的列。df pd.read_csv(‘input.csv‘, parse_dates[‘date_column‘])。Pandas会将其转换为datetime类型to_excel时会保持该类型Excel能正确识别。4. 方法二使用Openpyxl进行精细控制当你需要创建一个格式精美、带有特定样式的报表或者需要向一个现有的Excel模板中填入CSV数据时openpyxl是你的不二之选。4.1 从CSV到格式化的Excel报表下面的例子展示了如何将CSV数据写入Excel并添加标题、调整列宽、设置表头样式。import csv from openpyxl import Workbook from openpyxl.styles import Font, Alignment, Border, Side # 1. 创建新工作簿和工作表 wb Workbook() ws wb.active ws.title “销售数据” # 2. 设置标题行 title_cell ws[‘A1’] title_cell.value “2023年度销售数据报表” title_font Font(name‘微软雅黑’, size16, boldTrue, color“FF0000”) title_alignment Alignment(horizontal“center”, vertical“center”) title_cell.font title_font title_cell.alignment title_alignment ws.merge_cells(‘A1:E1’) # 合并第一行的A到E列作为标题 # 3. 读取CSV文件并写入数据 with open(‘sales.csv’, ‘r’, encoding‘utf-8-sig’) as f: csv_reader csv.reader(f) for row_idx, row in enumerate(csv_reader, start3): # 从第3行开始写数据标题占第1行表头占第2行 for col_idx, value in enumerate(row, start1): cell ws.cell(rowrow_idx, columncol_idx, valuevalue) # 4. 设置表头样式假设CSV第一行是表头现在在Excel的第2行 header_row 2 thin_border Border(leftSide(style‘thin’), rightSide(style‘thin’), topSide(style‘thin’), bottomSide(style‘thin’)) for col in range(1, ws.max_column 1): header_cell ws.cell(rowheader_row, columncol) header_cell.font Font(boldTrue) header_cell.alignment Alignment(horizontal“center”) header_cell.border thin_border # 5. 自动调整列宽近似 for column in ws.columns: max_length 0 column_letter column[0].column_letter # 获取列字母 for cell in column: try: if len(str(cell.value)) max_length: max_length len(str(cell.value)) except: pass adjusted_width (max_length 2) ws.column_dimensions[column_letter].width adjusted_width # 6. 保存文件 wb.save(‘formatted_sales_report.xlsx’)代码关键点解析ws.merge_cells(): 用于合并单元格制作跨列标题。openpyxl.styles: 这个模块包含了所有样式类如Font字体、Alignment对齐、Border边框、PatternFill填充等可以构建非常复杂的样式。列宽调整openpyxl没有真正的“自动调整列宽”功能上面的代码是一个常用模拟方案通过计算每列最长内容的长度来设置宽度。2是为了给单元格一点边距。4.2 向现有模板填充数据这是openpyxl非常强大的一个应用场景。你可以先设计好一个带有图表、公式、固定表头和格式的Excel模板文件template.xlsx然后只用Python向指定位置填充动态数据。from openpyxl import load_workbook # 1. 加载已存在的模板文件 wb load_workbook(‘report_template.xlsx’) ws wb[‘DataSheet’] # 切换到数据工作表 # 2. 假设我们知道数据应该从B5单元格开始填充 start_row 5 start_col 2 # 3. 读取CSV并填充 with open(‘latest_data.csv’, ‘r’, encoding‘utf-8-sig’) as f: csv_reader csv.reader(f) next(csv_reader) # 跳过CSV的表头行如果模板已有表头 for r_idx, row in enumerate(csv_reader, startstart_row): for c_idx, value in enumerate(row, startstart_col): ws.cell(rowr_idx, columnc_idx, valuevalue) # 4. 模板中的公式和图表会自动引用新填入的数据无需额外操作 wb.save(‘generated_report_Q4.xlsx’)注意事项使用模板时务必确保数据填充的起始位置不会覆盖模板中的公式、图表数据源区域或其他固定内容。最好在模板中预留出足够且明确的数据区域。5. 方法三使用XlsxWriter追求极致性能与高级功能如果你需要生成包含大量数据数十万行以上和复杂图表如组合图、趋势线的.xlsx报告并且对生成速度有要求XlsxWriter是性能之王。5.1 高效写入大量数据XlsxWriter采用了流式写入和常量内存模式的设计使其在处理大数据量时效率远超openpyxl。import csv import xlsxwriter # 1. 创建新Excel文件和工作表 workbook xlsxwriter.Workbook(‘large_dataset.xlsx’) worksheet workbook.add_worksheet(‘RawData’) # 2. 定义一些基础格式可选 header_format workbook.add_format({‘bold’: True, ‘bg_color’: ‘#C6EFCE’, ‘border’: 1}) # 3. 写入表头 with open(‘huge_data.csv’, ‘r’, encoding‘utf-8-sig’) as f: csv_reader csv.reader(f) headers next(csv_reader) # 读取第一行作为表头 for col_num, header in enumerate(headers): worksheet.write(0, col_num, header, header_format) # 行、列索引从0开始 # 4. 高效写入数据行 row_num 1 # 数据从第2行开始0-based索引所以是1 with open(‘huge_data.csv’, ‘r’, encoding‘utf-8-sig’) as f: csv_reader csv.reader(f) next(csv_reader) # 跳过已处理的表头 for row in csv_reader: for col_num, value in enumerate(row): worksheet.write(row_num, col_num, value) row_num 1 # 可以每写入一定行数打印进度 if row_num % 10000 0: print(f’已处理 {row_num} 行...’) # 5. 关闭工作簿这是必须的否则文件可能损坏 workbook.close()性能关键XlsxWriter的write()方法非常高效。它还有一个write_row()和write_column()方法可以一次写入一行或一列数据速度更快。对于超大数据可以考虑结合pandas的read_csv的chunksize用XlsxWriter分块写入。5.2 创建复杂图表与公式XlsxWriter的图表API非常强大支持几乎所有Excel原生图表类型。import xlsxwriter import pandas as pd # 假设我们有一个包含‘月份’和‘销售额’的DataFrame df pd.read_csv(‘monthly_sales.csv’) workbook xlsxwriter.Workbook(‘sales_report_with_chart.xlsx’) worksheet workbook.add_worksheet() # 写入数据 worksheet.write_row(‘A1’, [‘月份’ ‘销售额’]) # 表头 for i, (_, row) in enumerate(df.iterrows(), start1): worksheet.write(i, 0, row[‘月份’]) worksheet.write(i, 1, row[‘销售额’]) # 创建图表对象 chart workbook.add_chart({‘type’: ‘column’}) # 柱状图 # 配置图表数据系列 # 参数格式[sheet_name, first_row, first_col, last_row, last_col] chart.add_series({ ‘name’: ‘Sheet1!$B$1’, # 系列名称引用B1单元格 ‘categories’: ‘Sheet1!$A$2:$A${}’.format(len(df)1), ‘values’: ‘Sheet1!$B$2:$B${}’.format(len(df)1), ‘data_labels’: {‘value’: True}, # 在柱子上显示数值 }) # 设置图表标题和坐标轴 chart.set_title({‘name’: ‘月度销售额趋势’}) chart.set_x_axis({‘name’: ‘月份’}) chart.set_y_axis({‘name’: ‘销售额 (元)’}) # 将图表插入到工作表的指定位置 worksheet.insert_chart(‘D2’, chart) # 将图表左上角锚定在D2单元格 # 甚至可以添加一个带公式的汇总单元格 last_row len(df) 1 worksheet.write(last_row, 0, ‘总计’) worksheet.write_formula(last_row, 1, ‘SUM(B2:B{})’.format(last_row)) # 计算销售额总和 workbook.close()与Openpyxl的对比XlsxWriter在图表创建和格式的丰富性上通常更胜一筹且文档极其详尽。但记住它只能写不能读。如果你需要读取一个已有的Excel文件并修改必须使用openpyxl。6. 进阶技巧与疑难杂症解决掌握了基本方法后我们来看看那些容易踩坑的进阶问题。6.1 编码问题的深度处理中文乱码是CSV处理中最常见的问题其根源在于“编码不一致”。源文件编码探测如果不确定CSV的编码可以使用chardet库进行探测。import chardet with open(‘unknown.csv’, ‘rb’) as f: raw_data f.read(10000) # 读取前一部分字节用于检测 result chardet.detect(raw_data) encoding result[‘encoding’] confidence result[‘confidence’] print(f”检测到编码: {encoding} 置信度: {confidence}”)然后使用探测到的编码如GB2312GBK进行读取。写入Excel的编码对于pandas确保read_csv时使用了正确的编码。对于openpyxl和XlsxWriter它们写入的是Unicode字符串只要在读取CSV时解码正确写入就不会有问题。BOM头问题有些UTF-8编码的CSV文件带BOM头\xef\xbb\xbf。utf-8-sig编解码器能自动处理它读取时忽略写入时添加。如果使用open(… encoding‘utf-8’)读取带BOM的文件BOM会被当作第一个字符读入导致首列列名前多出奇怪字符。使用utf-8-sig即可完美解决。6.2 特殊字符与数据清洗CSV中的数据可能包含Excel解析有问题的字符。换行符单元格内的换行符\n在CSV中通常被引号包裹。pandas的read_csv默认能正确处理。但如果你用csv模块逐行读取需要确保使用csv.reader并设置正确的quoting参数如csv.QUOTE_MINIMAL它会自动处理引号内的换行符。分隔符与引号如果数据本身包含分隔符如逗号或引号CSV格式会用引号将整个字段括起来。pandas和csv模块都能标准处理。但要注意有时会遇到非标准的转义比如用反斜杠\”转义引号。这时可能需要指定escapechar参数。前置零与长数字从CSV读取身份证号、电话号码等以0开头的数字字符串或超过15位的长数字如信用卡号时Excel会默认将其转为数字并去掉前置零或用科学计数法显示。解决方案在写入Excel前将这些列的数据类型明确转换为字符串。在Pandas中可以用df[‘column’] df[‘column’].astype(str)。在openpyxl或XlsxWriter中直接写入字符串即可。更彻底的做法是在写入时为这些单元格设置文本格式。在openpyxl中可以设置单元格的number_format为‘’文本格式在XlsxWriter中可以创建一个格式对象str_format workbook.add_format({‘num_format’: ‘’})然后使用worksheet.write(… value, str_format)。6.3 性能优化与内存管理处理GB级别的CSV文件时需要特别关注内存和速度。Pandas分块处理Chunking如前所述使用chunksize。但注意如果最终需要将数据写入同一个工作表Pandas的ExcelWriter对于openpyxl引擎在追加模式mode‘a’下可能无法高效处理分块写入到同一张表。一个变通方法是分块处理并保存为多个临时文件最后再合并但这比较复杂。对于超大文件单表写入XlsxWriter是更好的选择。XlsxWriter的常量内存模式这是XlsxWriter的杀手锏。通过add_worksheet()时设置{‘constant_memory’: True}选项它会在写入时将行数据刷新到磁盘而不是全部保存在内存中极大降低了内存占用。workbook xlsxwriter.Workbook(‘huge_file.xlsx’) worksheet workbook.add_worksheet({‘constant_memory’: True}) # … 写入数据 … workbook.close()注意启用此模式后某些功能如合并单元格、自动筛选会受到限制或无法使用需查阅官方文档。数据类型优化在Pandas中使用dtype参数指定每列的数据类型如{‘col1’: ‘int32’ ‘col2’: ‘category’}可以大幅减少内存占用和提升读取速度。6.4 自动化与批处理脚本最后分享一个我常用的批处理脚本框架它可以遍历一个文件夹下的所有CSV文件将它们转换为Excel并统一处理一些常见问题。import os import pandas as pd from pathlib import Path def csv_to_excel_batch(input_folder, output_folder, output_format‘xlsx’): “”” 批量将指定文件夹内的CSV文件转换为Excel文件。 参数: input_folder: 存放CSV文件的文件夹路径 output_folder: 输出Excel文件的文件夹路径 output_format: 输出格式‘xlsx’ 或 ‘xls’ “”” input_path Path(input_folder) output_path Path(output_folder) output_path.mkdir(parentsTrue, exist_okTrue) # 创建输出文件夹 # 支持的CSV后缀 csv_extensions (‘.csv’ ‘.txt’) for csv_file in input_path.glob(“*”): if csv_file.suffix.lower() in csv_extensions: print(f”正在处理: {csv_file.name}”) try: # 尝试用常见编码读取可扩展 for encoding in [‘utf-8-sig’ ‘gbk’ ‘gb2312’ ‘utf-8’]: try: df pd.read_csv(csv_file, encodingencoding) print(f” 成功使用编码: {encoding}”) break except UnicodeDecodeError: continue else: print(f” 警告: 无法解码文件 {csv_file.name} 已跳过。”) continue # 简单的数据清洗去除字符串字段的首尾空格 df df.applymap(lambda x: x.strip() if isinstance(x, str) else x) # 构建输出文件路径 output_file output_path / f”{csv_file.stem}.{output_format}” # 根据格式选择引擎 engine ‘openpyxl’ if output_format ‘xlsx’ else ‘xlwt’ df.to_excel(output_file, indexFalse, engineengine) print(f” 已保存: {output_file.name}”) except Exception as e: print(f” 处理文件 {csv_file.name} 时出错: {e}”) print(“批量转换完成”) # 使用示例 if __name__ “__main__”: csv_to_excel_batch(‘./csv_files’ ‘./excel_output’ output_format‘xlsx’)这个脚本包含了编码自动探测、基础数据清洗和异常处理可以直接拿来修改使用。根据你的具体需求可以增加更多功能比如统一设置日期格式、为特定列添加数据验证等。
返回列表