news 2026/9/15 13:58:38

Python批量JSON转TXT:完整方案与工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python批量JSON转TXT:完整方案与工程实践

简介:这是一套Python批量处理JSON转TXT的小工具,面向需要在Python中频繁进行数据格式转换的开发者和数据分析人员,解决将多个JSON文件合并为单一TXT文件时的重复劳动。脚本基于内置json库实现,只需输入文件夹路径即可批量读取多个JSON文件,按需提取指定字段后汇总写入同一个TXT文件;代码结构清晰,修改少数参数就能适配不同需求,也可在此基础上增加错误处理、日志输出等能力,适合日常数据清洗与归档场景。压缩包容量仅2KB,包含2个Python脚本,分别承担主功能与JSON加载辅助,轻量易用,可快速集成到现有项目中。资源已有2494人浏览学习,说明其简便方案获得了不少使用者认可;对入门Python文件处理或希望简化重复性转换工作的读者来说,是一份可直接运行的实用模板,便于理解批处理思路并拓展更多数据转换功能。

1. 批处理 JSON 转 TXT:先想清楚"一个 TXT"长什么样

把几十个 JSON 文件合并成一个 TXT,这类需求在数据导出、日志归档、给下游模型或数据库灌数据时非常常见。很多人第一反应是写个循环逐个读取再追加写入,但真正决定脚本能不能复用的,是"转换"之外那三个问题:源文件是单对象还是 JSON 数组,目标 TXT 是每行一条记录还是自由文本,字段全部保留还是只抽业务字段。

这三个问题不先答完,写出来的批处理脚本换一批文件就得重改。本文用 Python 标准库 json 加 glob 完成整套方案,不引入第三方依赖,从最小脚本讲到嵌套取值、编码兜底和大文件流式解析,最后封装成带参数的命令行工具,并把输出校验写进流程。新手能照着改路径直接跑,熟手可以重点看 4.2 的编码探测和 5.3 的换行折叠两个容易被忽略的边界。

2. JSON 结构与目标格式:写转换脚本前先做的两个决定

2.1 先分清三种源文件形态:单对象、JSON 数组、JSONL

实际拿到的 JSON 文件很少长得一样。最常见的是三种:整个文件是一个对象,比如接口的一次响应;文件里是一个 JSON 数组,比如导出工具给的列表;以及 JSONL 格式,每行一个独立 JSON 对象,整个文件并不是一个合法的 JSON。这三种形态决定了你在哪一层取数据。

# 形态1:文件顶层是对象 {"code":0, "data":{"id":1}} import json with open('a.json', 'r', encoding='utf-8') as f: data = json.load(f) items = data.get('data', data) # 形态2:文件顶层是数组 [{"id":1}, {"id":2}] with open('b.json', 'r', encoding='utf-8') as f: data = json.load(f) items = data if isinstance(data, list) else [data] # 形态3:JSONL,一行一个对象 items = [] with open('c.jsonl', 'r', encoding='utf-8') as f: for line in f: if line.strip(): items.append(json.loads(line))

这里有个容易踩的坑:用 isinstance(data, list) 判断数组形态时,如果源文件顶层对象里某个业务字段本身就是 list,直接按数组处理会把整块数据错误展开。稳妥做法是先打印 type(data) 和顶层 key 确认一次,再决定解析入口,而不是只看某个子字段的类型就下结论。三种形态的分支写进同一个函数,靠一个参数切换,后续维护成本最低。

2.2 目标 TXT 的三种组织方式:每行一条、字段拼接、可读文本

合并后的 TXT 常见三种目标格式。每行一条完整 JSON 记录的优势是信息不丢、可以用 json.loads 逐行还原,排错也直观;字段按分隔符拼接适合直接灌数据库或 Excel;只提取指定字段写成带标签的文本则适合人工阅读和后续日志分析。三种格式的写出代码差异很小,但选错会直接影响下游消费。

# 格式A:每行一条完整 JSON fout.write(json.dumps(item, ensure_ascii=False) + '\n') # 格式B:只取字段,竖线分隔,表头单独写一行 fout.write(f"{item.get('id')}|{item.get('name')}|{item.get('time')}\n") # 格式C:可读文本,带字段标签 fout.write(f"[{item.get('time')}] {item.get('title')} {item.get('level')}\n")

我一般优先选"每行一个 JSON 对象",除非需求明确写了要哪些字段,因为这种格式后续无论是转 DataFrame、导入 Elasticsearch 还是做 diff,还原成本都是最低的。提醒一个细节:无论用哪种格式,都建议在文件开头写一行表头或格式说明,三个月后回看这个 TXT 时能立刻知道每一列是什么,而不是重新翻源文件比对。

2.3 选型:标准库 json 够用,什么时候才需要上 ijson

处理这类批任务,Python 标准库 json 是首选。它内置、零依赖、对绝大多数文件大小都足够快,代码写出来别人也能直接看懂。只有当单个 JSON 文件达到几百 MB 甚至上 GB、json.load 一次性把内存打满时,才需要换成 ijson 做流式解析,或者用 4.3 的 raw_decode 逐段解析。pandas 的 read_json 不是不能做,但对"转换成一个 TXT"这个任务,它多引入了 DataFrame 的概念,字段顺序和类型会被重排,反而容易引入意外。

一个判断依据:源文件总大小小于内存的十分之一,就用 json.load;超过这个比例,转流式方案。批处理任务里最常见的故障不是解析速度,而是单个大文件把进程 OOM 掉,后面的文件全部白跑。所以第 3 章的最小脚本里,每个文件的读取都放在独立上下文里,处理完立即释放引用,这是批量任务的基本纪律。

3. 用标准库实现 JSON 文件转 TXT 的批处理最小脚本

3.1 最小可用版本:glob 遍历加逐文件写入

先给一个能直接改路径就跑的版本。它的输入是一个目录,输出是一个合并后的 TXT,每个源文件里的每个 JSON 对象各占一行,兼顾单对象文件和 JSON 数组两种形态。

import json import glob def batch_json_to_txt(src_dir: str, out_file: str, encoding: str = 'utf-8') -> int: """把 src_dir 下所有 .json 文件合并写入 out_file,返回写入行数。""" files = sorted(glob.glob(f"{src_dir}/*.json")) written = 0 with open(out_file, 'w', encoding=encoding) as fout: for file in files: with open(file, 'r', encoding=encoding) as fin: data = json.load(fin) items = data if isinstance(data, list) else [data] for item in items: fout.write(json.dumps(item, ensure_ascii=False) + '\n') written += 1 return written if __name__ == '__main__': n = batch_json_to_txt('./json_files', './merged.txt') print(f'处理完成,共写入 {n} 行')

这段代码的逻辑可以拆成四层。glob.glob 负责把目录里所有 .json 文件名取出来,sorted 保证处理顺序稳定,在需要按文件名时间顺序合并时这一点很关键;json.load 把单个文件完整解析成 Python 对象;isinstance(data, list) 处理"顶层是数组还是对象"的分叉,两种形态都能进同一个写入循环;最后 json.dumps 用 ensure_ascii=False 保证中文直接以可读形式写进 TXT,而不是转成 \uXXXX 转义序列。输出文件只打开一次,循环写入后统一关闭,避免频繁开关文件句柄。

注意:输出文件的编码参数和输入文件的 encoding 用的是同一个变量,实际生产里两者可能不同。建议把输出编码固定为 utf-8,输入编码按源文件实际情况单独传参。

3.2 关键参数表:ensure_ascii、separators、sort_keys 怎么配

同样一段数据,json.dumps 的参数不同,产物差别很大。下面这几个参数是批处理场景里最常用的,indent 是类似 json 格式化工具里常见的美化参数,但合并成单行 TXT 时千万不能设,否则会破坏"每行一条记录"的结构。

参数取值示例作用建议
ensure_asciiFalse为 False 时中文原样输出,True 时输出 \uXXXX目标给人工看或导入中文系统时设 False
separators(',', ':')去掉 dumps 默认的空格,压缩单行体积每行一条记录时建议压缩,能省约 20% 体积
sort_keysTrue / False按键名排序输出需要 diff 两个批次结果时设 True
indent不设或 None美化缩进,会引入换行单行记录格式下不要设
default自定义函数处理 datetime、Decimal 等 json 不支持的类型的回调数据源带时间字段时必配

default 参数最容易翻车。源数据里混入 datetime、Decimal 这类对象时,json.dumps 会直接抛 TypeError: Object of type datetime is not JSON serializable,批处理跑到第 37 个文件才崩溃,前面的输出全部作废。常见做法是加一个兜底转换函数,把非 JSON 原生类型统一转成字符串或者用 ISO 格式输出。

def json_default(obj): # datetime/date 转成 ISO 字符串 if hasattr(obj, 'isoformat'): return obj.isoformat() # numpy 标量转成 Python 原生类型 if hasattr(obj, 'item'): return obj.item() return str(obj) line = json.dumps(item, ensure_ascii=False, default=json_default)

3.3 批量场景的三个常见误用

第一个误用是把整个合并循环包在一个大 try 里,遇到坏文件直接终止整个任务。批处理的价值恰恰在于"一个坏文件不能拖垮其余 99 个"。正确做法是单个文件失败记到日志里,continue 继续处理,全部结束后统一汇报失败清单。第二个常见误用是把所有文件读进一个 list 再统一写入,小文件没问题,但 200 个 10MB 的文件会吃进 2GB 内存;正确写法是读一个、写一个、丢引用。第三个误用是每个对象都 open 一次输出文件再 append,文件句柄和系统调用开销会让 10 万行数据的任务慢上几十倍。这几个问题改起来都不难,但都是线上跑批任务里真实出现过的故障点。

4. 嵌套取值、编码兜底与大文件流式解析

4.1 深层字段提取与缺键保护

如果目标是"只抽业务字段写进 TXT",那么 data['users'][0]['profile']['name'] 这种嵌套取值会很快变成一大串防御代码。更简洁的做法是写一个 deep_get 辅助函数,用点分路径表示层级,任何一层缺失都返回默认值,不抛 KeyError,批处理循环因此不用包满 try。

def deep_get(obj, dotted_path: str, default=''): """按 'a.b.c' 路径取嵌套值,key 缺失或类型不匹配时返回 default。""" for key in dotted_path.split('.'): if isinstance(obj, dict): obj = obj.get(key) else: return default if obj is None: return default return obj if obj is not None else default # 使用示例:取 item.owner.name,缺任何一个 key 都不会抛异常 row = f"{deep_get(item, 'id')}|{deep_get(item, 'owner.name')}\n"

这段代码的核心是把路径解析和取值分开。路径按 . 切分后逐层向下走,obj.get(key) 天然带缺键保护,isinstance(obj, dict) 防止在 list 或字符串上继续取属性。这个实现只覆盖 dict 嵌套,如果中间层是数组,可以扩展支持 'items.0.name' 这种数字下标,把 isinstance 判断改成同时接受 list 并用 int 下标访问。JSON 解析场景里嵌套多数到 dict 为止,这个深度已能覆盖大部分导出需求。

4.2 编码问题:UTF-8 BOM 与 GBK 源文件

现实里的 JSON 文件来源很杂。Windows 导出的常带 UTF-8 BOM,老业务系统的接口可能直接给 GBK 编码的文件。用固定 encoding='utf-8' 去读,遇到 BOM 会在顶层 key 前多出一个 \ufeff 字符,遇到 GBK 直接抛 UnicodeDecodeError。用"读字节、探测、解码"三步走,能在同一份代码里兼容三种编码。

from pathlib import Path import json def read_json_auto(path): raw = Path(path).read_bytes() # 按字节读入,绕过编码猜测 if raw.startswith(b'\xef\xbb\xbf'): # UTF-8 BOM return json.loads(raw.decode('utf-8-sig')) for enc in ('utf-8', 'gbk'): try: return json.loads(raw.decode(enc)) except UnicodeDecodeError: continue raise ValueError(f'无法解码文件: {path}')

判断顺序值得解释。先检查 BOM 是因为带 BOM 的 UTF-8 用 utf-8 解码不会报错,但会把 \ufeff 带进 key;utf-8-sig 会剥掉 BOM。之后按 utf-8、gbk 的顺序尝试,utf-8 是大多数现代文件的编码,把它放前面让成功率最高的路径最先命中,避免每次都先用 GBK 试错。decode 失败抛的是 UnicodeDecodeError,所以用 try 包住并 continue,全部失败才抛 ValueError。在这个函数外面接住异常,就能把文件路径记入失败日志而不是中断整个任务。

4.3 大文件流式解析:raw_decode 与逐行消费

单个 JSON 文件大到几百 MB 时,json.load 会把整个文件加载进内存,同时处理多个这种文件内存很容易吃紧。标准库有一个轻量替代:json.JSONDecoder().raw_decode 配合文件流,一次只解析一个 JSON 值,并把解析位置推进到该值结束。对 JSONL 这种天然逐行的格式尤其适用。

import json decoder = json.JSONDecoder() buf = '' with open('huge.jsonl', 'r', encoding='utf-8') as fin: for line in fin: stripped = line.strip() if stripped and stripped.startswith('{'): obj, idx = decoder.raw_decode(stripped) # obj 是单个字典对象,直接进入写入逻辑

raw_decode 返回两个值:解析出的对象和解析结束的下标。用在 JSONL 场景时,由于每行恰好是一个完整 JSON 值,raw_decode 一次消费整行,idx 恒等于行内容长度,所以多数情况只需要取 obj。它比 json.loads 强的地方在于天然的"解析一个、丢一个"的流式语义,不保留整个文件的引用。真正的超大多行数组(比如几 MB 的数组压在一行里)则建议上 ijson 的 items 接口按 key 迭代,那是为流式设计的库,标准库不硬撑。

5. 把批量脚本封装成命令行工具并验证输出

5.1 用 argparse 暴露目录与字段参数

固定路径的脚本只能自己用,换目录、换输出格式就得改代码。用 argparse 把输入目录、输出文件和抽取字段暴露成命令行参数,运维同事不碰 Python 源码也能跑。这里直接在 4.1 的 deep_get 基础上做字段抽取,路径里的点号表示嵌套层级。

import argparse import json import glob def main(): parser = argparse.ArgumentParser(description='批量 JSON 文件合并转 TXT') parser.add_argument('src', help='存放 JSON 文件的目录') parser.add_argument('--out', default='merged.txt', help='输出 TXT 路径') parser.add_argument('--fields', help='要提取的字段,逗号分隔,如 id,name,owner.name') parser.add_argument('--sep', default='|', help='字段分隔符,默认竖线') args = parser.parse_args() files = sorted(glob.glob(f"{args.src}/*.json")) written = 0 with open(args.out, 'w', encoding='utf-8') as fout: for file in files: try: with open(file, 'r', encoding='utf-8') as fin: data = json.load(fin) except (json.JSONDecodeError, UnicodeDecodeError) as exc: print(f'跳过 {file}: {exc}') continue items = data if isinstance(data, list) else [data] for item in items: if args.fields: values = [deep_get(item, f.strip()) for f in args.fields.split(',')] fout.write(args.sep.join(values) + '\n') else: fout.write(json.dumps(item, ensure_ascii=False) + '\n') written += 1 print(f'完成,共写入 {written} 行 -> {args.out}')

运行方式如下,第一个命令输出完整 JSON 行,第二个命令只抽三个字段并用逗号分隔。

python batch_json2txt.py ./json_files --out ./all.txt python batch_json2txt.py ./json_files --out ./names.txt --fields id,name,owner.name --sep ,

注意 --fields 与 --sep 是配套的,fields 为空时走完整 JSON 输出,sep 参数不生效。字段名本身不能含逗号和点号,这是命令行传参最容易踩的边界条件。

5.2 用行数核对和往返解析做输出校验

批处理输出很少有人逐条检查,所以校验要可量化。三个动作建议全做:统计输出行数并与源文件对象总数对比;抽 head 和 tail 各几行确认没有乱码和半截记录;对每行 JSON 再做一次 json.loads,能还原说明合并没有破坏数据。

bad = 0 with open('merged.txt', 'r', encoding='utf-8') as f: for i, line in enumerate(f, 1): if line.strip(): try: json.loads(line) except json.JSONDecodeError: bad += 1 print(f'第 {i} 行无法解析') print(f'解析失败行数: {bad}')

因为目标格式是"每行一个合法 JSON",这重校验不依赖业务知识就能判断文件完整性——只要有一行被截断或两行粘在一起,json.loads 必然抛异常。如果目标格式是字段拼接,则把校验换成"按分隔符拆列,检查列数是否恒定",这样能抓到内容里混入分隔符导致的串列问题,那是字段拼接格式最隐蔽的坑。

5.3 折叠字段内换行,保证一行一条记录

最后是一个实战斗了很久才总结的细节。字段值里本身含换行符时,json.dumps 之后换行会被转成 \n 转义序列,所以"每行一条 JSON"格式下数据不会被拆行;但字段拼接格式下,字段值里的换行会直接破坏行结构,灌库时整表错位。处理方式是在拼接前统一做空白折叠。

def clean(value): if not isinstance(value, str): return value return ' '.join(value.split()) # 把 \n \t 连续空格折叠为单个空格

把每个字段值先过 clean 再拼接,输出的每一行都能保持"一行一条记录"的结构。这个函数放在字段抽取的列表推导里,一行改动就能避免下游导入时的整表错位。批量 JSON 转 TXT 的脚本写到这一步,就覆盖了日常导出、归档、灌库三类主要场景的完整链路:解析入口按文件形态切换,取值路径按业务字段配置,编码兜底应对来源杂的旧数据,输出校验保证交付物可用。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 13:58:19

UI-TARS 快速指南:把 GUI 模型的输出跑成自动化动作

UI-TARS 快速指南:把 GUI 模型的输出跑成自动化动作 【免费下载链接】UI-TARS Pioneering Automated GUI Interaction with Native Agents 项目地址: https://gitcode.com/GitHub_Trending/ui/UI-TARS 你让视觉模型看一张截图,它回你一行字&#…

作者头像 李华
网站建设 2026/9/15 13:58:04

良品铺子网站规划和建设到底多少钱?域名服务器避坑指南

良品铺子网站规划和建设到底多少钱?域名服务器避坑指南 域名服务器搞不懂,报价单看两眼就头晕,这是很多项目经理在做【良品铺子网站规划和建设】时最头疼的事。别急,今天不聊虚的,直接拆解这笔账。很多人问【良品铺子网站规划和建设】多少钱,其实钱花在哪里,决定了你的网站是“能用”还是“好用”。…

作者头像 李华
网站建设 2026/9/15 13:57:03

文件上传漏洞从攻击到防御:绕过手法、代码审计与加固实践

做安全的这些年,如果说哪个漏洞让我觉得“看似不起眼、实际特别致命”,文件上传漏洞绝对排得上前三名。很多开发同学觉得上传功能不过就是“接收文件、存到服务器”,能有什么风险?可真出了问题,往往就是服务器直接被拿…

作者头像 李华
网站建设 2026/9/15 13:56:23

网页数据一键变可编辑Excel:Skill开发全流程拆解与避坑指南

最近整理了一个新的 Skill,名字很直白:把网页数据直接变成一张能编辑的表格。给 Claude Code、Codex 这类编程代理丢一个链接,它就能自动把页面里的数据抓下来,整理成 Excel 或 CSV,打开就能改。听起来就是“网页采集”…

作者头像 李华