ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python流式拆分超大CSV文件,告别Excel卡死

Python流式拆分超大CSV文件,告别Excel卡死 简介该款CSV拆分工具面向需要处理大型数据文件的MATLAB用户与数据分析人员可将超出导入限制的CSV文件按行数或大小分割为多个小文件避免内存溢出并提升导入效率。工具支持自定义每份子文件的行数或目标大小自动批量输出到指定目录省去手动分割的繁琐。压缩包共3个文件包含绿色免安装的主程序exe、详细说明的htm文档及来源快捷方式整个包仅10KB轻量便携。资源已有1136人学习下载适用于Excel、Python等数据处理场景也可作为自动化拆分的轻量替代。配合MATLAB的readtable等命令分批导入时可显著降低内存占用该工具为1.0绿色免费版无需安装、随取随用无论是拆分千万级日志记录还是分块分析超大表格都能有效减少等待时间与系统资源消耗。对于初学者它提供了友好的使用说明便于快速掌握数据分块技巧对于中高级分析师则能提升大批量数据处理的自动化程度具有实用价值。 CSV文件在手里Excel打开就卡死这种场景我都不知道遇到多少回了。尤其是从数据库导出的报表、爬虫抓下来的数据集、或者传感器日志动辄上百万行任何常规工具都吃不消。我一贯的做法就是先把大文件拆成小文件用 csv 拆分工具分成可控的块再去处理后面的分析、入库、清洗。这篇文章我就把这个工具从需求分析到代码实现再到实际踩坑的过程完整讲一遍希望能给被大表格折磨的朋友一个直接能抄的作业。拆 CSV 这件事听起来特别基础但实际做起来坑不少。拆分维度怎么选、要不要保留表头、编码怎么处理、字段里有逗号和换行怎么办这些问题不提前想清楚工具写出来也是半残废。我最初写这个工具就是为了应付一个 500 万行的电力负荷数据文件后来不断加需求慢慢就变成了一个比较完整的版本这里分享给你。1. 需求剖析CSV 文件为什么非拆不可1.1 拆分的常见触发场景先说说什么情况下你才真正需要拆分而不是硬扛。我大概归纳了四类高频场景Excel 或 WPS 打开 CSV 直接卡死、未响应或者只加载出一部分数据。Excel 单个工作表上限是 104 万多行超过这个数字基本没戏。程序导入 CSV 超时比如 SQL Server 导入向导在解析大文件时非常容易断掉或者内存占用直接飙满。数据处理工具对文件大小有硬限制比如某些可视化分析平台只允许上传 50MB 以内的文件。需要把数据并行处理比如要分发到多个机器上跑任务或者多个人分工处理不同批次。这些场景的共同特点都是数据量级超过了某个工具的承载力边界。与其去调工具的参数不如先把文件切成能处理的大小。拆分这个动作本身很简单但拆多大、怎么拆需要根据后续工具的限制来决定。1.2 四种拆分维度选哪种取决于目标CSV 文件拆分并不是只有“多少行切一刀”这一种玩法。我实际用下来主流的拆分维度有四种每种对应不同的使用场景拆分维度实现思路典型场景按行数拆分每 N 行写一个新文件Excel 打开、分批导入数据库按文件数拆分自动计算每份行数分成 M 份并行处理、任务分发按字段值拆分相同字段值的记录合并到一个文件按日期、地区、品牌分组按文件大小拆分按字节数切分上传平台有大小限制时百分比行数拆分最省事也是默认方案按字段值拆分则更高级一点比如我处理过的手机价格预测数据集就是按“品牌”字段拆成多个文件方便分别建模训练。选择哪种方式本质上取决于你拆分后要做什么。如果是给人看的按行数拆分最合适如果是给程序做分类处理的按字段值拆分更有价值。2. 方案选型用什么工具拆最省事2.1 Python csv 模块 vs pandas我的选择实现 CSV 拆分的方案不少。用纯手工文本处理可以用 pandas 也行命令行工具也有但综合考虑稳定性和可控性我最终选择用 Python 的 csv 标准模块来写核心逻辑。pandas 的read_csv也确实能拆但问题在于它默认会把整个文件读进内存再切片写出去。500 万行的文件光读进来就要占好几个 G 内存要是跨文件做字段拆分时内存翻倍普通笔记本直接就扛不住了。而且 pandas 强依赖 DataFrame 的列类型推断有些 CSV 里混着脏数据读的时候会各种报警告。csv 标准库实现的是流式读写一次只处理一行文件多大都不怕内存占用始终维持在一个很低的水平。csv.reader能正确处理带引号的字段、内嵌逗号、内嵌换行这类边界情况这也是手写 split 函数容易忽略的坑。2.2 流式处理拆大文件的核心原理拆 CSV 大文件的底层原理其实就一句话把文件当作一个迭代器逐行处理而不是一次性加载全部内容。Python 中打开的文件对象本身就是一个迭代器用for row in reader循环时它按行从磁盘读取读一行处理一行。你要做的只是设定一个计数器记录当前文件已经写了多少行达到阈值后关闭当前文件句柄创建下一个新文件继续写。流式处理听起来没有技术含量但它是整个拆分工具性能的根基。只要不用readlines()把整个文件加载到内存百万行级别的 CSV 在脚本里都只是“花时间处理”的问题而不是“机器能不能扛得住”的问题。我在旧笔记本上测试过500 万行、约 800MB 的 CSV按行数拆成 50 个文件耗时大概 40 秒左右内存占用始终没有超过 100MB。3. 实操实现一个能直接用的 csv 拆分脚本3.1 按行数拆分最通用的一版代码先上最核心、也最实用的版本按指定行数拆分自动保留表头。这里有一个细节值得注意我用utf-8-sig编码写入文件这样拆出来的文件用 Excel 打开时不会出现中文乱码。import csv import os def split_csv_by_rows(src_path, out_dir, rows_per_file100000, has_headerTrue): 按行数拆分CSV文件 :param src_path: 源CSV文件路径 :param out_dir: 输出目录 :param rows_per_file: 每个文件包含的数据行数 :param has_header: 源文件是否有表头 os.makedirs(out_dir, exist_okTrue) base_name os.path.splitext(os.path.basename(src_path))[0] with open(src_path, r, encodingutf-8-sig, newline) as f: reader csv.reader(f) header None if has_header: try: header next(reader) except StopIteration: print(空文件无需拆分) return file_index 1 line_count 0 current_writer None current_file None for row in reader: if line_count 0: out_path os.path.join( out_dir, f{base_name}_part_{file_index:03d}.csv ) current_file open(out_path, w, encodingutf-8-sig, newline) current_writer csv.writer(current_file) if header is not None: current_writer.writerow(header) current_writer.writerow(row) line_count 1 if line_count rows_per_file: current_file.close() file_index 1 line_count 0 if current_file is not None: current_file.close() print(f拆分完成共生成 {file_index} 个文件保存在 {out_dir})使用方式很简单python split_csv.py --input huge_data.csv --out split_data --rows 100000文件命名用_part_001.csv这样的格式001的前导零非常重要。字母排序时part_010会正确排在part_002后面如果你用part_1、part_2、part_10这种命名方式排序就全乱了。3.2 按字段值拆分按日期、品牌或地区分组有些需求不是按固定行数切而是要把相同类别的数据放到一起。比如电力负荷数据气象 CSV里面每条记录都带有日期、地区和负荷值你可能需要按日期拆成每天一个文件方便后续对每天的负荷情况做分析。这个版本与按行数拆分的区别在于它需要先读取表头找到目标字段的索引然后为每个不同的字段值维护一个文件句柄。实现时稍要注意上下文管理文件句柄多了要及时关闭否则超过系统限制就会报“Too many open files”错误。import csv import os def split_csv_by_column(src_path, out_dir, column_name, encodingutf-8-sig): 按字段值拆分CSV文件相同字段值的记录写入同一个文件 :param src_path: 源CSV文件路径 :param out_dir: 输出目录 :param column_name: 作为分组依据的列名 os.makedirs(out_dir, exist_okTrue) base_name os.path.splitext(os.path.basename(src_path))[0] with open(src_path, r, encodingencoding, newline) as f: reader csv.reader(f) header next(reader) if column_name not in header: raise ValueError(f列名 {column_name} 不存在当前表头为{header}) col_index header.index(column_name) file_handlers {} for row in reader: if len(row) col_index: continue key row[col_index].strip() if not key: key unknown if key not in file_handlers: safe_key .join( c if c not in \\/:*?| else _ for c in key ) out_path os.path.join( out_dir, f{base_name}_{safe_key}.csv ) fh open(out_path, w, encodingencoding, newline) writer csv.writer(fh) writer.writerow(header) file_handlers[key] (fh, writer) fh, writer file_handlers[key] writer.writerow(row) for fh, _ in file_handlers.values(): fh.close() print(f按字段 {column_name} 拆分完成共生成 {len(file_handlers)} 个文件)如果某个字段值本身太长或者含有特殊字符不适合直接做文件名最好做一次清理。我上面已经处理了 Windows 文件名的非法字符但建议在实际使用中再限制一下文件名长度比如超过 50 个字符就截断否则很可能在某些机器上报错。3.3 封装成命令行工具日常直接调用把逻辑写成函数只是第一步日常使用还得有方便的命令行入口。我顺手用argparse做了个简单的 CLI支持指定输入文件、输出目录、拆分方式和目标行数import argparse def main(): parser argparse.ArgumentParser(descriptionCSV 文件拆分工具) parser.add_argument(--input, requiredTrue, help输入的CSV文件路径) parser.add_argument(--out, requiredTrue, help输出目录) parser.add_argument(--mode, choices[rows, column], defaultrows) parser.add_argument(--rows, typeint, default100000, help按行数拆分时的行数阈值) parser.add_argument(--column, defaultNone, help按字段拆分时的列名) args parser.parse_args() if args.mode rows: split_csv_by_rows(args.input, args.out, args.rows) else: if not args.column: parser.error(--mode column 时必须通过 --column 指定列名) split_csv_by_column(args.input, args.out, args.column) if __name__ __main__: main()加了这个入口之后整个工具就可以脱离编辑器直接使用了。甚至可以把它复制到系统 PATH 目录下取名叫csvsplit.py然后任何目录下都可以随时执行csvsplit.py --input D:\data\2024_load.csv --out D:\data\split --mode column --column date提示如果你是在 Windows 上使用想双击就运行可以再写一个.bat封装文件但更推荐是加到环境变量里这样哪种姿势调用都方便。4. 常见问题与排坑实录4.1 拆出来的文件用 Excel 打开变乱码这个问题一开始让我很头疼。当时我按行数拆分后发给同事对方打开文件看到一堆乱码第一反应就是我代码写错了。后来排查了一圈发现不是拆分逻辑的问题而是编码问题。源文件是 UTF-8 编码写入时也是 UTF-8按理说没问题。问题是 Excel 在 Windows 上打开 CSV 文件时默认按 ANSIGBK编码解析除非文件开头有 UTF-8 的 BOM 标记它才会自动切换识别。解决办法就是在打开输出文件时指定encodingutf-8-sigPython 会向文件头部写入一个不可见的 BOM 头Excel 看到这个标记后就会正确识别为 UTF-8。我上面的代码已经把这个处理写进去了你就别再把utf-8-sig改回utf-8了不然大概率又得踩一次坑。4.2 内存占用居高不下读到一半卡死如果你的拆分脚本跑了半天内存蹭蹭往上涨最后系统卡死那基本可以断定是在某个地方用了readlines()或者一次性把所有数据装进了列表。有的朋友会把 csv.reader 包一层list()或者用pandas.read_csv读完整文件这些操作在大文件面前都是灾难。csv.reader 本身是流式的你只在for row in reader循环里逐行处理内存就不会出问题。另外一个比较容易忽略的是文件句柄泄漏。在按字段值拆分时如果字段种类特别多比如几万个不同的 ID每个 key 都打开一个文件文件句柄就会耗尽。遇到这种情况要么改成“先收集再统一写”的两阶段方案要么分批处理别让打开的句柄数超过系统限制。4.3 表头处理每个拆分文件都要保留表头吗这个看使用场景。如果你想用 Excel 打开看或者继续导入数据库那每个拆分文件都应该保留表头否则使用者还得自己补列名。但如果你想用拆分后的文件去做模型训练或者把多个文件再合并回去那表头只需要出现在第一个文件里后面的文件全都是纯数据反而更干净。我习惯在脚本参数里单独留一个has_header开关。拆之前自己心里要清楚源文件有没有表头以及目标场景需不需要表头。我甚至见过有人把表头当成数据行拆分到不同文件里的情况拆完之后每个文件的第一行都奇奇怪怪的这种低级错误多注意就行。4.4 字段中含有逗号、引号、换行时怎么办这是新手从零手写拆分时最容易翻车的地方。CSV 的字段并不是“按逗号分割”那么简单它是支持引号转义机制的。比如一个字段是张,三里面的逗号是字段内容不是分隔符如果字段里还有引号就会写成你好这种形式甚至字段内部可以包含换行符。如果你用line.split(,)这种粗暴方式拆出来的结果就完全错乱了。所以核心建议是用标准库csv模块来读和写不要自己动手做字符串分割。csv.reader和csv.writer会严格按照 CSV 的引用规则处理绝大部分边界情况它都能兜住。我见过很多自己写正则拆 CSV 的项目最后都在数据含引号时翻车了真没必要重复造这个轮子。5. 从拆分到延伸csv 工具的更多用法5.1 拆分 转格式顺带处理 blt、isf 等数据文件有人在网上搜“blt 转 csv”、“isf 转 csv”其实这和 CSV 拆分是同一类问题。blt、isf 这些格式本质上是某种特定结构的文本文件只是字段分隔方式或元数据格式不同。解析它们的核心思路和解析 CSV 完全一样逐行读取提取字段然后按 CSV 规则写入。我遇到过一次 ISF 格式的仪器数据文件每条记录前面还有一段特殊前缀注释。处理方式就是先用 Python 读入跳过非数据行剩下的按字段解析最后用 csv.writer 写出标准 CSV。这之后再去做数据分析和入库就会顺畅很多。所以这个拆分工具其实是一个“文本数据标准化”的雏形稍微改改就能处理很多非标准格式。5.2 拆分 清洗去重一次搞定拆文件的过程中其实完全可以顺带做一些简单的清洗操作。比如在按字段值拆分的循环里加一个去重集合相同主键的记录只保留第一条再比如统一把某些列的空值替换成默认值或者剔除完全为空的整行数据。这个方案比“先拆完再去清洗”要省一遍 IO 时间。因为大文件的读写是非常耗时的能在一个循环里做完的事情就尽量减少遍历次数。我处理手机价格预测数据集时就做过这种组合操作一边按“品牌”拆分一边把价格列为空的记录过滤掉省了不少时间。但建议清洗逻辑不要写在基础拆分函数里而是通过参数控制是否启用。否则工具就变成了一个“多功能臃肿工具”反而破坏了拆分工具的简单性和可复用性。5.3 从 CSV 到数据库拆完再导入更稳拆分工具最常见的后续动作就是配合数据库导入使用。SQL Server 的导入向导在读取大 CSV 时经常会超时卡死而拆成几十个小文件之后逐个导入就非常顺利。我在一次项目中需要把一个 2GB 左右的库表导出数据导入到测试环境。源文件行数太多SSMS 向导根本读不完。我先用工具按 50 万行拆成了 40 多个 CSV然后逐个通过向导导入每个文件导入大约十几秒整个过程非常稳定。这个思路也适用于很多其他数据库工具像 MySQL Workbench、Navicat甚至某些 BI 平台的上传功能。CSV 的拆分本质上就是给数据管道的“最大限制”做适配。5.4 一个建议把拆分工具固定下来但别过度设计最后我想说的是这种工具最忌讳的是一次性写死、用完就删。你把它固定成一个命令行小工具放在手边说不定哪一天就会用到。但也不要过度设计非得给它加个图形界面、加一堆高级参数。核心的按行拆分、按字段拆分、编码处理、表头保留这几个功能已经能覆盖 90% 的真实需求了。在实际操作中我每次处理一个新的 CSV 之前都会习惯性地先看一眼文件大小和行数再决定要不要拆。如果在 Windows 上可以用 Notepad 或者 VS Code 打开文件查看在 Linux 服务器上wc -l一行命令就能统计行数。数据量小的文件没必要拆拆了反而增加管理成本只有超过工具边界的时候拆分这个动作才有真正的价值。本文还有配套的精品资源点击获取
返回列表