尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
批量Excel转CSV工具:pandas+glob+click实战指南
简介这是一款面向Windows平台开发者的轻量级Excel批量转CSV工具专为需高效处理大量xls/xlsx报表的办公自动化、数据清洗及ETL预处理场景设计。资源包含完整VS2005工程含sln/dsw/vcproj等项目文件、C源码7个头文件与5个cpp实现、编译后的可执行文件ExcelToCsv.exe以及测试用例xls/xlsx/csv样本和辅助资源图标、对话框类、SDK兼容性修复代码。压缩包共33个文件大小仅94KB结构清晰便于快速理解工程组织与Excel解析逻辑——尤其对Font类与Windows SDK冲突的修改方案具有典型参考价值。已有2680人学习下载开发者可直接运行bin目录下的exe完成一键转换亦可深入研究源码学习COM组件调用、Excel格式解析及跨版本兼容性调试技巧。1. 批量Excel转csv工具为什么你还在手动双击、另存为、点三次鼠标某天凌晨两点A同学在实验室赶数据清洗任务手边堆着37个命名混乱的Excel文件——有的叫“2024_Q3_销售明细_v2_final(1).xlsx”有的是“data_副本.xlsx”还有的Sheet名写着“原始未处理勿删”。他第11次右键→打开→另存为→选CSV→确认→关掉→再点下一个……直到Excel弹出“内存不足”警告才意识到这不是效率问题是工具缺失引发的重复劳动雪崩。批量Excel转csv工具本质不是“多开几个窗口”而是用确定性逻辑接管不确定的人工操作自动识别.xlsx/.xls混合格式、跳过隐藏Sheet、统一编码防乱码、保留原始日期数值精度、按规则重命名输出文件。它适合三类人数据标注工程师要喂给YOLO或BERT的原始表格、财务岗需每日导出对账CSV进BI系统、以及所有被“另存为”耗尽耐心的Python新手。别信“Excel自带导出”——它不批量、不幂等、不记录失败项更不会告诉你第23个文件因公式循环引用而静默丢了一整列。2. 用pandasglob在本地跑通最小可行脚本5行代码撑起整个流程2.1 环境准备与依赖安装只装真正需要的包提示不要用pip install pandas openpyxl xlrd全量安装。xlrd从2.0版起已彻底放弃对.xlsx支持强行装会报Unsupported format, or corrupt fileopenpyxl专精.xlsx但无法读.xlsxlrd旧版1.2.0能读.xls却不能读.xlsx。正确组合是pandas调度层openpyxl读.xlsxxlrd2.0读.xls——但更稳妥的做法是让pandas自动选引擎。pip install pandas openpyxl # 如果必须处理.xls文件再加 pip install xlrd2.0安装后验证是否可用import pandas as pd # 测试能否读取两种格式 try: pd.read_excel(test.xlsx, engineopenpyxl) # 应成功 print(✅ openpyxl可用) except Exception as e: print(❌ openpyxl异常:, str(e)) try: pd.read_excel(test.xls, enginexlrd) # 若有.xls则测试 print(✅ xlrd可用) except Exception as e: print(⚠️ xlrd不可用无.xls文件可跳过)逻辑说明pandas.read_excel()底层会根据文件扩展名自动匹配引擎但显式指定engine能避免歧义。.xlsx强制走openpyxl快、稳定、支持样式元数据.xls走xlrd2.0唯一兼容方案。不推荐用pyxlsb或calamine——它们解决的是小众格式如.xlsb反而增加维护成本。2.2 核心转换脚本带路径解析、Sheet遍历与错误隔离import os import glob import pandas as pd from pathlib import Path def excel_to_csv_batch(input_dir: str, output_dir: str, include_hidden_sheets: bool False, encoding: str utf-8-sig): 批量将Excel文件转为CSV支持.xlsx和.xls混合目录 :param input_dir: 输入Excel所在文件夹路径 :param output_dir: 输出CSV保存路径自动创建 :param include_hidden_sheets: 是否导出隐藏Sheet默认False :param encoding: CSV编码默认utf-8-sig兼容Excel中文打开 # 创建输出目录 Path(output_dir).mkdir(parentsTrue, exist_okTrue) # 匹配所有Excel文件区分大小写覆盖.XLSX/.xls等 excel_files [] for ext in [*.xlsx, *.xls, *.XLSX, *.XLS]: excel_files.extend(glob.glob(os.path.join(input_dir, ext))) if not excel_files: print(f⚠️ 没有找到Excel文件请检查路径{input_dir}) return success_count 0 failed_files [] for excel_path in excel_files: try: # 解析原始文件名与基础名 file_stem Path(excel_path).stem file_ext Path(excel_path).suffix.lower() # 读取Excel工作簿对象不加载数据仅获取Sheet名 if file_ext .xlsx: excel_obj pd.ExcelFile(excel_path, engineopenpyxl) else: # .xls excel_obj pd.ExcelFile(excel_path, enginexlrd) # 遍历每个Sheet for sheet_name in excel_obj.sheet_names: # 跳过隐藏Sheetopenpyxl可识别xlrd不支持故统一跳过 if not include_hidden_sheets: # openpyxl方式检测隐藏xlrd无API保守策略跳过以_开头的Sheet名 if hasattr(excel_obj, book) and hasattr(excel_obj.book, worksheets): ws excel_obj.book[sheet_name] if getattr(ws, hidden, False): continue elif sheet_name.startswith(_): continue # 读取当前Sheet数据 df excel_obj.parse(sheet_name) # 构造CSV文件名原文件名_表名.csv safe_sheet_name .join(c for c in sheet_name if c.isalnum() or c in _-) csv_filename f{file_stem}_{safe_sheet_name}.csv csv_path os.path.join(output_dir, csv_filename) # 写入CSV关键参数说明 # indexFalse不写行索引Excel无此概念加了反而干扰下游 # encodingencodingutf-8-sig在Windows Excel中能正确显示中文 # errorsreplace遇到非法字符如\x00时替换为避免中断 df.to_csv(csv_path, indexFalse, encodingencoding, errorsreplace) print(f✅ {excel_path} → {csv_path}) success_count 1 except Exception as e: error_msg f{excel_path} 处理失败{str(e)} print(f❌ {error_msg}) failed_files.append(error_msg) print(f\n 完成统计成功 {success_count} 个CSV失败 {len(failed_files)} 个) if failed_files: print( 失败详情) for err in failed_files: print(f • {err}) # 使用示例直接运行 if __name__ __main__: excel_to_csv_batch( input_dir./input_excels, # ← 改为你自己的输入路径 output_dir./output_csvs, # ← 改为你自己的输出路径 include_hidden_sheetsFalse, encodingutf-8-sig )参数说明include_hidden_sheetsFalse生产环境强烈建议关闭。隐藏Sheet常含中间计算逻辑或调试数据导出易引发下游误解。encodingutf-8-sig这是Windows上Excel打开CSV不乱码的唯一可靠编码。utf-8在Excel里会显示为乱码gbk在Linux/macOS可能崩溃。errorsreplace比ignore更安全——ignore会静默丢字符replace至少留个提示你这里有脏数据。3. 用click封装成命令行工具支持通配符、递归、日志与进度条3.1 安装click并初始化CLI结构pip install click tqdmclick比argparse更适合构建专业级CLI自动补全、子命令分组、类型校验、帮助文档生成。我们不做花哨功能只聚焦三个刚需① 支持*.xlsx通配符输入如./input/*.xlsx② 递归扫描子目录--recursive③ 输出详细日志到文件--log-file3.2 CLI主程序把函数变成可执行命令#!/usr/bin/env python3 # 文件名excel2csv.py import click import logging from pathlib import Path from tqdm import tqdm # 配置日志同时输出到控制台和文件 def setup_logger(log_file: str None): logger logging.getLogger(excel2csv) logger.setLevel(logging.INFO) formatter logging.Formatter( %(asctime)s - %(levelname)s - %(message)s, datefmt%Y-%m-%d %H:%M:%S ) # 控制台处理器 console_handler logging.StreamHandler() console_handler.setFormatter(formatter) logger.addHandler(console_handler) # 文件处理器可选 if log_file: file_handler logging.FileHandler(log_file, encodingutf-8) file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger click.command() click.argument(input_pattern, typestr, requiredTrue) click.option(-o, --output-dir, typeclick.Path(file_okayFalse), default./output_csvs, help输出CSV目录默认./output_csvs) click.option(--recursive, is_flagTrue, help递归扫描子目录) click.option(--include-hidden, is_flagTrue, help导出隐藏Sheet慎用) click.option(--encoding, typestr, defaultutf-8-sig, helpCSV编码默认utf-8-sigWindows Excel友好) click.option(--log-file, typestr, help日志文件路径如run.log) def main(input_pattern, output_dir, recursive, include_hidden, encoding, log_file): 批量Excel转CSV工具支持.xlsx/.xls混合、多Sheet、错误隔离 INPUT_PATTERN支持通配符如 ./data/*.xlsx 或 C:\\files\\report_*.xls logger setup_logger(log_file) logger.info(f启动转换输入模式{input_pattern}输出目录{output_dir}) # 解析输入路径支持相对/绝对、通配符 input_paths list(Path(.).glob(input_pattern)) if not input_paths and * not in input_pattern: # 若无通配符且路径不存在尝试作为普通路径 p Path(input_pattern) if p.exists(): input_paths [p] if not input_paths: logger.error(f未匹配到任何文件{input_pattern}) return # 递归收集所有Excel文件 excel_files [] for p in input_paths: if p.is_file() and p.suffix.lower() in [.xlsx, .xls, .XLSX, .XLS]: excel_files.append(p) elif p.is_dir() and recursive: for ext in [*.xlsx, *.xls, *.XLSX, *.XLS]: excel_files.extend(list(p.rglob(ext))) if not excel_files: logger.error(未找到任何Excel文件) return logger.info(f共发现 {len(excel_files)} 个Excel文件) # 导入核心函数避免循环导入 from convert_core import excel_to_csv_batch # 执行转换带tqdm进度条 success_count 0 failed_count 0 for excel_path in tqdm(excel_files, desc正在处理, unitfile): try: excel_to_csv_batch( input_dirstr(excel_path.parent), output_diroutput_dir, include_hidden_sheetsinclude_hidden, encodingencoding ) success_count 1 except Exception as e: logger.error(f文件 {excel_path} 处理异常{e}) failed_count 1 logger.info(f✅ 转换完成成功 {success_count}失败 {failed_count}) if __name__ __main__: main()注意此脚本需与上一节的convert_core.py含excel_to_csv_batch函数放在同一目录。tqdm进度条在Jupyter中可能显示异常建议在终端运行。使用示例# 基础用法当前目录下所有.xlsx python excel2csv.py *.xlsx # 递归扫描data目录及其子目录 python excel2csv.py data/**/* --recursive # 指定输出目录 记录日志 python excel2csv.py reports/*.xls -o ./clean_data --log-file convert.log # 导出隐藏Sheet仅调试用 python excel2csv.py debug/*.xlsx --include-hidden4. 避坑5个真实踩过的坑与血泪解决方案4.1 现象CSV用Excel打开全是乱码但用VS Code看是正常的原因编码设置错误。utf-8在Windows Excel中会被识别为ANSI中文变“涓枃”gbk在macOS/Linux中会报错。解决必须用utf-8-sig。它在文件开头写入BOM\ufeffExcel据此识别为UTF-8。其他编码一律不兼容跨平台。4.2 现象日期列导出后变成43831.0这样的数字原因Excel内部用“自1900-01-01起的天数”存储日期pandas默认不自动转换。解决在excel_obj.parse()中加parse_dates参数或后续用pd.to_datetime()。更稳妥做法是在调用parse时指定dtypedf excel_obj.parse(sheet_name, dtype{订单日期: string}) # 先当字符串读再统一转 # 后续统一处理 df[订单日期] pd.to_datetime(df[订单日期], errorscoerce)4.3 现象某个Excel文件报错ValueError: This application does not support TLS 1.0 or 1.1原因该Excel由新版Office加密保存启用TLS握手openpyxl旧版本不支持。解决升级openpyxl到最新版pip install --upgrade openpyxl若仍失败说明文件被密码保护——本工具不支持解密需人工用Excel输入密码后另存为无密码文件。4.4 现象输出CSV中空行变NULL或数字末尾多出.0如123.0原因pandas将整数列自动识别为float64因Excel允许单元格混合类型导出时保留小数。解决在to_csv()前做类型清洗# 遍历每列对纯整数列转int跳过含NaN的列 for col in df.columns: if df[col].dropna().apply(float.is_integer).all(): df[col] pd.to_numeric(df[col], downcastinteger, errorsignore)4.5 现象处理大文件100MB时内存爆满、程序卡死原因pandas.read_excel()默认加载全部Sheet全部数据到内存无流式读取。解决改用chunksize分块读取仅适用于单Sheet大表# 在parse时加参数需确认该Sheet无合并单元格否则chunk会错位 df_iter excel_obj.parse(sheet_name, chunksize10000) for i, chunk in enumerate(df_iter): chunk.to_csv(f{base_name}_{sheet_name}_part{i}.csv, indexFalse, encodingutf-8-sig)⚠️ 注意chunksize不适用于含合并单元格、复杂公式或跨Sheet引用的文件——此时只能靠升级机器内存或拆分源文件。5. 进阶技巧用配置文件管理规则、自动重命名与字段标准化5.1 为什么需要配置文件——告别硬编码的“改一行测十次”当你开始处理来自不同部门的Excel销售部的文件列名是“客户ID”采购部叫“供应商编码”财务部写“cust_no”——手动df.rename(columns{...})会随需求爆炸式增长。配置文件把业务规则从代码中剥离让非程序员也能维护映射关系。我们设计一个config.yaml比JSON更易读支持注释# config.yaml rules: - source_pattern: sales_*.xlsx # 匹配文件名 sheet_filter: 明细表|Data # 正则匹配Sheet名 column_mapping: 客户名称: customer_name 下单日期: order_date 金额(元): amount_cny date_columns: [order_date] numeric_columns: [amount_cny] - source_pattern: purchase_*.xls sheet_filter: ^采购单$ column_mapping: 供应商编码: supplier_id 物料号: material_code 入库数量: qty_in numeric_columns: [qty_in] output: naming_template: {source_stem}_{rule_index}_{sheet_name}_{timestamp} timestamp_format: %Y%m%d_%H%M%S encoding: utf-8-sig5.2 加载配置并动态应用规则的Python模块# config_loader.py import yaml import re from datetime import datetime from pathlib import Path def load_config(config_path: str) - dict: with open(config_path, r, encodingutf-8) as f: return yaml.safe_load(f) def match_rule(filename: str, sheet_name: str, config: dict) - dict: 根据文件名和Sheet名匹配最优先规则 for rule in config.get(rules, []): if re.match(rule[source_pattern], filename): if sheet_filter not in rule or re.search(rule[sheet_filter], sheet_name): return rule return {} def apply_column_mapping(df: pd.DataFrame, mapping: dict) - pd.DataFrame: 按配置重命名列并标准化数据类型 df df.rename(columnsmapping) # 日期列转换 for col in mapping.values(): if col in mapping.get(date_columns, []): df[col] pd.to_datetime(df[col], errorscoerce) # 数值列转换 for col in mapping.values(): if col in mapping.get(numeric_columns, []): df[col] pd.to_numeric(df[col], errorscoerce) return df def generate_output_name(config: dict, source_stem: str, sheet_name: str, rule_index: int 0) - str: 按模板生成CSV文件名 ts datetime.now().strftime(config[output][timestamp_format]) name config[output][naming_template].format( source_stemsource_stem, rule_indexrule_index, sheet_namesheet_name.replace( , _), timestampts ) return f{name}.csv5.3 在主流程中集成配置驱动修改excel_to_csv_batch函数在解析完Sheet后插入规则匹配# 在原函数中df excel_obj.parse(...)之后添加 config load_config(./config.yaml) # 假设配置文件在同级目录 rule match_rule(Path(excel_path).name, sheet_name, config) if rule: df apply_column_mapping(df, rule.get(column_mapping, {})) csv_filename generate_output_name( config, file_stem, sheet_name, rule_indexlist(config[rules]).index(rule) if rule in config[rules] else 0 ) else: # 无匹配规则用默认命名 csv_filename f{file_stem}_{safe_sheet_name}.csv csv_path os.path.join(output_dir, csv_filename)✅ 效果销售部传来的sales_Q3_2024.xlsx→ 自动映射列名、转日期、输出sales_Q3_2024_0_明细表_20241025_143022.csv采购部的purchase_oct.xls→ 用第二套规则处理。新增业务线只需改YAML不动一行Python。6. 验证与交付如何证明你的工具真的可靠6.1 构建最小验证集3类必测文件不要等上线后再翻车。我给自己定的铁律每次更新代码先跑通这3个文件——它们覆盖了90%的线上故障场景文件名类型设计目的验证点test_mixed.xlsx.xlsx混合格式主力能否读取.xlsx、跳过隐藏Sheet、正确编码test_legacy.xls.xls老系统遗留xlrd2.0是否生效、日期列是否保持为字符串test_edge_case.xlsx.xlsx边界压力测试含合并单元格、空行、特殊字符®™€、10万行数据验证脚本verify_tool.pyimport subprocess import sys def run_test(): # 清空输出目录 subprocess.run([rm, -rf, ./test_output]) # 执行转换 result subprocess.run([ sys.executable, excel2csv.py, test_data/*.xlsx, test_data/*.xls, -o, ./test_output, --log-file, ./test_output/verify.log ], capture_outputTrue, textTrue) # 检查日志关键词 with open(./test_output/verify.log) as f: log f.read() assert ✅ 转换完成 in log, 转换未完成 assert 成功 3 in log, 未处理全部3个文件 assert len(list(Path(./test_output).glob(*.csv))) 5, CSV数量不符应为52个xlsx各2个Sheet1个xls的1个Sheet print( 验证通过基础功能、混合格式、边界文件全部OK) if __name__ __main__: run_test()6.2 给同事交付时的3句真话比文档管用“它不修数据只转格式”明确划清责任边界。如果Excel里“金额”列混着文本“N/A”和数字123导出后还是这样——清洗是下一步的事本工具绝不擅自填充或删除。“失败文件会单独记在log里路径精确到Sheet”运维最怕黑匣子。我们的log里会写“data/report.xls → Sheet 汇总 失败xlrd.biffh.XLRDError: Unsupported format, or corrupt file”而不是笼统的“第5个文件错了”。“配置文件改完立刻生效不用重启”业务方提需求“采购单要加一列‘税率’”你改完YAMLta双击运行脚本就看到新CSV——这才是降低协作成本的关键。最后说句实在的我写这个工具的第7版时删掉了所有“智能识别列语义”“自动补全缺失值”的玄学功能。因为真正的批量处理核心从来不是“多聪明”而是每一次执行都给出完全相同的结果。稳定压倒一切。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

C++状态模式在工业控制系统中的应用与实践

C++状态模式在工业控制系统中的应用与实践

1. 状态模式基础认知我第一次接触状态模式是在开发一个工业控制系统的报警模块时。系统需要根据设备的不同运行状态(待机、运行、故障、维护)触发差异化的报警策略,如果直接用if-else堆砌条件判断,代码很快就会变成难以维护的&quo…

📅 2026/10/15 15:02:18
火星全球地形渲染实践:基于四叉树与LOD的精细调度

火星全球地形渲染实践:基于四叉树与LOD的精细调度

做火星全球地形渲染这件事,一开始我以为最麻烦的是“火星长什么样”,后来才发现真正的硬骨头在“怎么把几十亿个采样点塞进显卡里还能流畅转起来”。四叉树LOD这套组合,就是目前解决全球大尺度地形渲染最务实的一条路。这篇笔记我把整个实现过…

📅 2026/10/15 15:02:18
新骆驼IPTV完美版后端源码部署与二次开发实战指南

新骆驼IPTV完美版后端源码部署与二次开发实战指南

简介:这份资源是新骆驼IPTV完美版的后端源码与安卓APP源码压缩包,面向具备一定安卓或服务端基础的开发者,用于研究电视直播系统的完整实现,并支持二次开发与功能自定义。包内以后端服务与前端应用代码为主,涵盖服务器管…

📅 2026/10/15 15:02:18
MORE NEWS

更多资讯

📰

2026 零基础 AI 大模型学习路线:从入门到上手,照着走少走 90% 弯路

很多人想入门大模型,却一开始就被劝退:数学不好是不是学不了?知识点又多又杂,从哪开始?学了一堆理论,还是不会做项目?网上资料碎片化,越学越混乱我可以明确告诉你:零基础…

📰

Il2CppDumper实战:Unity IL2CPP逆向符号恢复与IDA/Ghidra衔接指南

简介:面向 Unity 游戏逆向与安全分析人员的 IL2CPP 元数据还原工具包,专门解决 IL2CPP 编译产物在静态分析中难以直接获得类型与结构信息的问题。还原出的 DLL 文件虽然不包含实际代码,却能用于提取 MonoBehaviour 与 MonoScript,…

📰

H5商城压缩包跑通与部署避坑指南

简介:这是一套以必要APP为原型高仿的H5手机端商城静态页面,面向需要练习移动端布局、组件拆分与交互实现的前端学习者,也适合作为课程设计或练手项目的参考模板。压缩包共133个文件,约2.02MB,其中34个html页面覆盖首页…

📰

Qt6音视频实时传输:QML+多线程+RTP推流全链路实现

简介:本资源是一套基于Qt框架实现网络摄像头音视频实时传输的完整工程方案,面向嵌入式开发、音视频传输及Qt跨平台应用开发者,重点解决QML层缺乏录音API导致音频无法实时采集与传输的技术难点。方案采用C多线程架构,在主线程运行Q…

📰

ARM串口调试实战:minicom配置、日志抓取与避坑指南

简介:这是一份面向嵌入式开发者的minicom串口调试工具源码包,适用于在Linux环境下对ARM架构设备进行系统移植、内核日志查看与驱动调试的工程师及学习者。资源共包含189个文件,以46个C源文件与22个头文件为核心实现,辅以17个in模板…

📰

URL百分号编码原理与Python实战指南

1. 百分号不是“乱码”,而是URL里最沉默的翻译官你有没有点开一个链接,地址栏里突然冒出一串带%20、%E4%B8%AD、%3A这种字符的网址?第一反应可能是:“这谁看得懂?是不是发错了?”——其实它比你想象中更懂你…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬