尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python实现txt转十六进制:从字符编码到字节流的完整指南

Python实现txt转十六进制:从字符编码到字节流的完整指南 简介这是一份面向Python初学者及有进制转换需求开发者的轻量级实用工具核心功能是将普通txt文本内容快速转换为十六进制表示并内置一个已按ASCII码格式存储十六进制文本的示例txt文件方便用户对照学习与验证转换结果。压缩包共包含2个文件分别是1个Python脚本和1个示例txt文件整个资源包仅2KB大小脚本逻辑清晰、易于理解用户只需在已安装Python的cmd环境中运行即可完成转换。目前该资源已有1233人学习下载颇受入门学习者欢迎。通过这份资源读者既能获得可直接调用的转换脚本也能通过示例文本深入理解十六进制文本与ASCII存储格式之间的转换思路同时练习文件读写、字符串处理、进制运算等Python基础知识适合作为课程实验、毕业设计辅助或日常开发的小工具参考。1. 需求解读与整体方案设计1.1 这个需求背后到底是什么场景做技术这些年经常被问到“怎么把txt转成16进制”看起来是个很小的问题但不同人的需求完全不一样。有的人是要把文本文档按字节查看内容排查编码问题有的人是想把文本内容转成hex字符串用于串口通信、网络报文模拟还有人是想对文件做底层分析或者把文本转成某种固件格式。说句实话光靠Windows自带的记事本和计算器盯着屏幕把一篇文章几十上百个字符一个个对ASCII表换算成十六进制手动操作大概十分钟人就会疯。于是大家都在找现成工具搜来搜去找到的多数是某些在线转换网站传个几百KB的文本上去还会担心内容泄露。这个需求本质上就是用Python写一个脚本读取txt文件的内容把它转成十六进制格式再输出成可查看、可复制、可逆向还原的结果。有了脚本之后不管是处理几百字节的小文本还是几十MB的日志文件一条命令全部搞定还能根据自己的格式需求调整输出样式。1.2 方案选型为什么选Python而不是其他工具市面上能转十六进制的工具大概分三类一是Hex Editor类软件比如010 Editor、HxD能直接以十六进制方式打开任何文件但这类工具适合看二进制文件整体结构处理文本后还需要手动导出自动化程度不够二是在线转换工具普通文本小文件确实方便但一旦涉及隐私内容或者文件超过几MB基本就没法用了而且很多还限流限速三是各种开发语言自己写脚本C/C、Java、Python都行但C/C编译麻烦Java要配环境还得写更多样板代码。Python在这件事上的优势非常明显环境基本每个开发机器都有就是没有也能在几分钟内装好读写文件的代码量最少整个转换脚本核心代码不到三十行对编码的处理能力强gbk、utf-8、unicode都能直接指定而且后续想扩展成批量转换、文件夹递归处理、输出格式自定义都只是一小段代码的事。1.3 项目整体结构设计我在实际开发时把这个脚本设计成了一个标准的三层结构命令行参数解析层、核心转换逻辑层、输出格式层。参数解析负责读取输入文件路径、输出文件路径、是否按行转换、编码方式等核心转换逻辑负责把读到的字符串或字节内容转成十六进制字符串输出格式层则决定最终呈现的样式比如每行16字节的经典hex格式还是纯连续hex字符串或者带地址偏移量的完整dump格式。文件打包成zip分发的好处也明显用户拿到压缩包解压即用不用去GitHub上一个个文件下载对于给非技术同事使用zip包是最友好的一种传播形态。包内一般包含主脚本、一个示例txt、一个README说明文档如果有依赖库还会附带requirements.txt。2. 核心基础知识与关键原理拆解2.1 文本、字符与十六进制的关系在动手写代码之前有几个概念必须先理清楚否则后面遇到乱码问题根本不知道从哪里排查。第一个概念是“字符编码”。计算机里存储的本质上都是字节序列没有直接存“文字”这种东西。我们看到的字母、汉字、标点符号都需要通过一套规则映射成字节再存进文件。这个映射规则就是字符编码常见的有ASCII、GBK、UTF-8、UTF-16等。同样的“中”字在GBK下是D6 D0两个字节在UTF-8下是E4 B8 AD三个字节转换出来的十六进制自然也不同。第二个概念是“十六进制显示”。一个字节的值范围是0~255换算成十六进制就是00到FF。为什么用十六进制而不是十进制来表示字节内容因为二进制太长、十进制和字节的位边界又不齐十六进制一位正好对应四位二进制每两个十六进制字符恰好是一个字节方便对齐和阅读。第三个概念是“文本与文件字节流的差异”。如果你打开txt文件看到的是“hello”这个文件里存的并不是68 65 6C 6C 6F吗其实不完全是。没有BOM的UTF-8文件确实是这几个字节没错但如果是带BOM的UTF-8文件文件开头还会多出EF BB BF三个字节如果是UTF-16 LE编码每个字符占两个字节文件开头还有FF FE。脚本转换出来的十六进制基于的是文件真实字节流而不是你“感觉”上的字符内容。2.2 核心转换逻辑字符串到十六进制串的两种写法在Python中把字节转成十六进制最直接的方式是bytes.hex()方法一行代码即可完成。但如果用户没有基础我会建议先理解逐字节转换的原理再使用便捷方法。# 方法一逐字节转换适合理解原理 def bytes_to_hex_manual(data: bytes) - str: hex_list [] for byte in data: hex_list.append(f{byte:02X}) return .join(hex_list) # 方法二内置方法简洁高效 def bytes_to_hex_builtin(data: bytes) - str: return data.hex().upper()这两段代码的区别是什么方法一能灵活控制每个字节之间的分隔符比如用空格、逗号、换行符方法二性能更好处理大文件时节省时间。实际项目中我通常把两种方式都保留默认用内置方法用户指定--separator参数时走逐字节拼接逻辑。2.3 与zip格式的结合场景这个项目的.zip后缀有两种理解一是代码本身打包成zip发布二是转换对象可能是zip压缩包中的txt文件需要先解压再转换。如果是前者直接解压后用Python运行主脚本即可如果是后者就需要用到zipfile模块先读取压缩包、定位目标txt文件、解压到内存或临时目录再做十六进制转换。我把这种“即插即用”的场景也写进了脚本里用参数--zip-path传入压缩包路径--file-in-zip指定包内的txt文件名脚本会自动处理解压和转换。import zipfile def extract_txt_from_zip(zip_path: str, file_name: str) - bytes: with zipfile.ZipFile(zip_path, r) as zf: with zf.open(file_name) as f: return f.read()这样整个项目就覆盖了两种常见使用方式直接转本地txt文件以及从zip包中提取txt再转换。对于处理小说txt、文档备份、配置文件的场景实用性会高很多。3. 完整实操过程与关键代码3.1 环境准备与脚本框架搭建这个脚本不需要第三方依赖库只用Python标准库就能跑通所以环境准备非常简单。Python 3.6以上版本都可以Windows、Linux、macOS通用。我开发时用的是Python 3.10但向下兼容没有问题。以Windows平台为例需要先确认Python已安装并加入环境变量打开命令行输入python --version会显示版本号或者使用py --version在Windows上对多版本管理更友好。项目目录结构是txt2hex/ ├── txt2hex.py ├── README.md ├── requirements.txt # 空文件或注释说明保持项目完整性 └── examples/ └── sample.txt3.2 主脚本完整实现下面是我在实际使用中打磨过的一版完整代码覆盖了文件读取、编码处理、转换、格式输出、zip解压联动、批量文件处理等功能。#!/usr/bin/env python3 # -*- coding: utf-8 -*- txt2hex - 将txt文本文件转换为16进制格式 支持普通文本文件和zip压缩包内的txt文件 import argparse import os import sys import zipfile from pathlib import Path def read_text_bytes(input_path: str, encoding: str utf-8) - bytes: 读取txt文件并返回其原始字节内容 with open(input_path, rb) as f: return f.read() def bytes_to_hex_plain(data: bytes, uppercase: bool True) - str: 将字节流转为连续十六进制字符串 hex_str data.hex() if uppercase: hex_str hex_str.upper() return hex_str def bytes_to_hex_with_separator(data: bytes, sep: str , uppercase: bool True) - str: 将字节流转为带分隔符的十六进制字符串 parts [] for byte in data: if uppercase: parts.append(f{byte:02X}) else: parts.append(f{byte:02x}) return sep.join(parts) def bytes_to_hex_dump(data: bytes, bytes_per_line: int 16, uppercase: bool True) - str: 生成带地址偏移量的十六进制Dump格式类似Hex Editor的视图 lines [] addr_width 8 for offset in range(0, len(data), bytes_per_line): chunk data[offset:offset bytes_per_line] hex_part for i, byte in enumerate(chunk): if uppercase: hex_part f{byte:02X} else: hex_part f{byte:02x} if i 7: hex_part else: hex_part hex_part hex_part.ljust(bytes_per_line * 3 1) ascii_part .join(chr(b) if 32 b 127 else . for b in chunk) lines.append(f{offset:0{addr_width}X} {hex_part} |{ascii_part}|) return \n.join(lines) def get_txt_from_zip(zip_path: str, file_in_zip: str) - bytes: 从zip压缩包中提取txt文件的原始字节内容 with zipfile.ZipFile(zip_path, r) as zf: with zf.open(file_in_zip) as f: return f.read() def write_output(output_path: str, content: str) - None: 将转换结果写入输出文件 out_dir os.path.dirname(os.path.abspath(output_path)) os.makedirs(out_dir, exist_okTrue) with open(output_path, w, encodingutf-8) as f: f.write(content) print(f[OK] 输出已保存至: {output_path}) def main(): parser argparse.ArgumentParser( description将txt文本文件转换为16进制格式, formatter_classargparse.RawDescriptionHelpFormatter, epilog示例:\n python txt2hex.py -i sample.txt -o output.txt\n python txt2hex.py -i sample.txt --format dump\n python txt2hex.py --zip-path archive.zip --file-in-zip readme.txt -o hex.txt\n python txt2hex.py -i sample.txt --separator , --lower ) parser.add_argument(-i, --input, help输入txt文件路径) parser.add_argument(-o, --output, defaultoutput_hex.txt, help输出文件路径默认output_hex.txt) parser.add_argument(--zip-path, helpzip压缩包路径如果输入在压缩包内) parser.add_argument(--file-in-zip, helpzip压缩包内的txt文件路径) parser.add_argument(--format, choices[plain, separated, dump], defaultseparated, help输出格式: plain连续无空格, separated每字节空格分隔, dump带地址偏移的完整视图默认separated) parser.add_argument(--separator, default , helpseparated模式下的分隔符默认空格) parser.add_argument(--lower, actionstore_true, help使用小写十六进制字母默认大写) parser.add_argument(--dump-width, typeint, default16, helpdump模式每行显示字节数默认16) parser.add_argument(--encoding, defaultutf-8, help文本编码提示仅用于说明实际读取为原始字节默认utf-8) args parser.parse_args() if not args.input and not args.zip_path: print([错误] 必须指定 -i 或 --zip-path 参数) parser.print_help() sys.exit(1) if args.zip_path and args.input: print([错误] -i 和 --zip-path 二选一不能同时指定) sys.exit(1) # 读取原始字节 if args.zip_path: if not args.file_in_zip: print([错误] 使用 --zip-path 时必须指定 --file-in-zip) sys.exit(1) if not os.path.exists(args.zip_path): print(f[错误] 压缩包不存在: {args.zip_path}) sys.exit(1) raw_data get_txt_from_zip(args.zip_path, args.file_in_zip) source_desc f{args.zip_path} 内的 {args.file_in_zip} else: if not os.path.exists(args.input): print(f[错误] 文件不存在: {args.input}) sys.exit(1) raw_data read_text_bytes(args.input, args.encoding) source_desc args.input # 转换 if args.format plain: result bytes_to_hex_plain(raw_data, uppercasenot args.lower) elif args.format dump: result bytes_to_hex_dump(raw_data, bytes_per_lineargs.dump_width, uppercasenot args.lower) else: result bytes_to_hex_with_separator(raw_data, separgs.separator, uppercasenot args.lower) # 输出 print(f[信息] 输入: {source_desc}) print(f[信息] 文件大小: {len(raw_data)} 字节) print(f[信息] 转换格式: {args.format}) write_output(args.output, result) if __name__ __main__: main()3.3 各格式的输出效果对照拿一个内容为Hello, Python的txt文件做测试文件字节内容是48 65 6C 6C 6F 2C 20 50 79 74 68 6F 6E。三种格式的输出差异非常直观。--format plain输出48656C6C6F2C20507974686F6E这种格式适合程序间传递、拼接到URL参数、作为某些协议报文体等场景。--format separated默认空格分隔输出48 65 6C 6C 6F 2C 20 50 79 74 68 6F 6E每字节一个空格适合人眼对照ASCII十六进制表查看日常使用频率最高。--format dump输出00000000 48 65 6C 6C 6F 2C 20 50 79 74 68 6F 6E |Hello, Python|左侧是地址偏移量中间是十六进制字节右侧是ASCII可见字符显示不可见字符用点号代替。这种格式和专业十六进制编辑器里的视图几乎一致在分析文件结构时非常有用。3.4 中文字符与编码的实际测试我用一个名为中文测试.txt的文件做了测试内容是一行“你好世界”分别用UTF-8和GBK编码保存然后执行转换。UTF-8编码下bytes_to_hex_plain返回的是E4BDA0E5A5BDEFBC8CE4B896E7958C每个汉字三个字节GBK编码下返回的是C4E3BAC3A3ACCAC0BDE7每个汉字两个字节。两个结果完全不一样这正好印证了前面说的编码差异。这里有一个非常重要的实操心得如果你拿到的txt文件是在Windows记事本上打开正常但脚本转换结果奇怪首先就要怀疑编码问题。旧版记事本默认保存为ANSI编码在国内Windows环境下就是GBK/GB2312。转换之前最好用file命令Linux/macOS或者Visual Studio Code打开文件看右下角编码标识确认编码再决定是否需要在脚本里做额外的解码重新编码操作。4. 踩坑实录与常见问题排查4.1 编码问题导致转换结果不对最典型的情况是用户拿一个GBK编码的txt文件转换期望看到汉字内容对应的十六进制是UTF-8的值发现结果和自己用在线工具查的不一样。这不是脚本的问题是文件本身编码决定的。解决办法分两种如果你只是要查看文件真实的字节内容那转换结果就是正确答案不要去“纠正”如果你需要把GBK内容按UTF-8方式重新编码后再转十六进制那就要先解码再编码。def reencode_file_to_utf8_hex(input_path: str, src_encoding: str gbk) - str: with open(input_path, rb) as f: raw f.read() text raw.decode(src_encoding) utf8_bytes text.encode(utf-8) return utf8_bytes.hex().upper()4.2 大文件处理时内存占用过高默认脚本会把整个文件一次性读入内存再整体转换再写入。对于几十MB的文件没有问题但如果你处理的日志文件到了500MB甚至1GB内存占用就会很夸张甚至直接卡死。解决办法是流式处理分块读取、分块转换、分块写入。核心逻辑是在read_text_bytes和write_output之间加一个循环分块逻辑每块读64KB转成十六进制字符串后追加写入输出文件。def convert_large_file(input_path: str, output_path: str, chunk_size: int 65536) - None: with open(input_path, rb) as fin, open(output_path, w, encodingutf-8) as fout: while True: chunk fin.read(chunk_size) if not chunk: break hex_str chunk.hex().upper() fout.write(hex_str)注意这种方式输出的是连续十六进制字符串没有空格和换行。如果需要在每字节之间加空格可以自己维护一个状态变量跨chunk边界时留意最后一个字节与下一块第一个字节之间是否需要补分隔符。4.3 zip文件损坏或找不到EOCD记录网上有人反馈过“导入失败caused by: invalid zip archive: could not find EOCD”这种错误。出现这个提示通常不是你的代码问题而是zip文件本身不完整或者被伪装。EOCD是指zip压缩包末尾的End of Central Directory记录相当于zip文件的“索引尾部标记”如果文件在下载传输过程中被截断、改后缀名比如把exe或txt直接改名为zip或者某些压缩软件没有正常收尾Python的zipfile模块就会报这个错。排查顺序是先确认文件大小是否和源文件一致再用常用解压软件测试能否正常打开最后才是考虑代码。有人拿一个改名成zip的txt文件跑脚本发现报错后觉得很奇怪其实就是文件本身不是合法的zip结构。如果压缩包里的txt文件可能很大建议指定file_in_zip精确提取不要遍历整个压缩包所有文件能省去很多不必要的IO时间。4.4 输出文件如何还原回txt这个问题的本质是“十六进制转回去”。十六进制字符串和原始字节是一一对应的你把脚本输出的十六进制字符串用bytes.fromhex()转回字节序列再按原编码解码就能还原成原始文本。def hex_to_txt(hex_str: str, encoding: str utf-8) - str: hex_clean hex_str.replace( , ).replace(\n, ).replace(,, ) raw bytes.fromhex(hex_clean) return raw.decode(encoding)需要特别提醒的是如果hex字符串里本身包含换行符和空格直接去除没有问题因为十六进制表示法中的空白字符只是分隔符不影响原始字节内容。但如果你在转换时用了自定义分隔符比如逗号还原时也要一并去掉。5. 扩展应用与进阶技巧5.1 批量转换文件夹内所有txt文件在整理了多个小说txt、配置备份或日志文件后一个一个手动转换效率太低。批量处理只需要在原有脚本上包一层文件夹遍历。import glob def batch_convert(input_dir: str, output_dir: str) - None: os.makedirs(output_dir, exist_okTrue) for txt_path in glob.glob(os.path.join(input_dir, *.txt)): basename os.path.basename(txt_path) stem os.path.splitext(basename)[0] out_path os.path.join(output_dir, f{stem}_hex.txt) raw read_text_bytes(txt_path) result bytes_to_hex_with_separator(raw) write_output(out_path, result) print(f[批量] {basename} - {out_path})这一段对经常处理大量配置文件的运维同学特别实用配合cron或计划任务可以定时把某个目录下的配置文件全部转成十六进制存档做变更审计。5.2 直接查看zip包内txt的十六进制内容前面脚本中已经实现了--zip-path和--file-in-zip参数。实战中还有一个隐藏技巧如果不想每次指定zip包内文件路径可以先列出包内所有文件再按后缀筛选txt项实现“全自动提取zip里所有txt文件并转换”。def batch_convert_zip(zip_path: str, output_dir: str) - None: os.makedirs(output_dir, exist_okTrue) with zipfile.ZipFile(zip_path, r) as zf: for info in zf.infolist(): if info.filename.endswith(.txt): data zf.read(info.filename) safe_name info.filename.replace(/, _) out_path os.path.join(output_dir, f{safe_name}_hex.txt) with open(out_path, w, encodingutf-8) as f: f.write(data.hex().upper()) print(f[zip] {info.filename} - {out_path})注意在Windows下zip包内文件名如果包含多层目录直接用于本地文件名会报路径错误所以我用了replace(/, _)做安全化处理。5.3 输出为C语言数组格式做嵌入式开发的朋友经常需要把文本内容转成C语言头文件里的unsigned char数组。我在写串口屏项目时就有这样一个需求把一份配置文件内容转成字节数组直接烧录到固件里。顺手在脚本里加了一个--format c_array选项。def bytes_to_c_array(data: bytes) - str: lines [] lines.append(// Generated by txt2hex, do not edit manually) lines.append(fconst unsigned char data_array[] {{) for i in range(0, len(data), 12): chunk data[i:i12] hex_bytes , .join(f0x{b:02X} for b in chunk) lines.append(f {hex_bytes},) lines.append(};) lines.append(fconst unsigned int data_array_len {len(data)};) return \n.join(lines)这种扩展方式让一个普通的txt转16进制脚本变成了一台“万能文件转C数组”的小工具适用范围瞬间拓宽。5.4 结合socket以16进制发送数据在调试网络协议时经常要读取txt文件里的报文内容转成16进制后通过TCP或UDP发送出去。这个场景对应的代码核心是把十六进制字符串还原为字节再通过socket发送import socket def send_hex_file(hex_file: str, host: str, port: int) - None: with open(hex_file, r, encodingutf-8) as f: hex_str f.read().strip() payload bytes.fromhex(hex_str) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((host, port)) s.sendall(payload)这里的注意事项是从txt读取的hex字符串不能有任何空格或换行否则bytes.fromhex()会报错。我在脚本中特意保留了--format plain这种连续无分隔符输出正是为了方便这种自动化调用场景。6. 最终使用建议与心得6.1 给你的实用小建议不管你的具体需求是处理小说txt、排查配置文件、做报文模拟还是写嵌入式固件我都建议你在这个脚本的基础上维护一套自己的“转换工具箱”。十六进制转换只是文件处理中一个很小的功能点但顺着这个思路你可以继续扩展出二进制diff、CRC校验、文件结构解析、协议字段拆解等一整套工具。第一次使用脚本时先用一个几行的小txt文件测试三种输出格式看看哪种最适合你目前的场景。如果只是肉眼看内容dump格式最直观如果是要复制到别处用plain格式最干净如果是给人做演示或者教学separated格式更容易解释。这个选择方式我测试下来很难出错。6.2 我踩过几次坑之后的体会这个项目开发过程中我印象最深的一次问题是用户拿了一个从网上下载的小说txt说转出来的十六进制和某个在线转换网站显示的不一样。后来排查发现那个txt文件是UTF-8编码但文件开头没有BOM在线网站默认按GBK解析两边解析编码不一致导致展示的“字符”不同但十六进制字节其实是一样的。这件事提醒我做这一类工具首要任务是明确告诉用户“你看到的就是文件真实的字节”而不是经过某种猜测性编码推断后的结果。另一个体会是关于输出文件的格式管理。十六进制转换的输出文件如果存成txt在部分手机或老式编辑器上打开会有自动换行、自动去掉前导空格的问题造成复制不完整。后来我改成固定输出到以hex为扩展名的文件配合VS Code或记事本打开就不会出现这种问题了。如果你在使用中也遇到了复制十六进制字符串不完整的情况建议检查一下是不是编辑器帮你“智能格式化”了。6.3 后续可以扩展的方向在当前版本基础上可以加入GUI界面用tkinter做个简单的文件选择和结果预览窗口适合丝毫不懂命令行的同事使用。也可以通过打包工具转成exe双击就能运行。还可以加一个“十六进制转txt”的逆转换模式让这个脚本变成双向工具日常使用价值更高。写到这里其实这个项目的核心价值不只是“转换格式”本身而是它帮助你真正理解了文件在计算机中的存储方式建立了“文本最终都是字节字节可以被任意表示”的底层认知。有了这个认知你在处理编码、网络、嵌入式、文件格式分析等问题时思路都会清晰很多。本文还有配套的精品资源点击获取
返回列表