
玩MTK手机刷机的朋友对这几个词一定不陌生BROM、DA、scatter、PGPT。很多人拿SP Flash Tool刷机时第一步就是选一个scatter引导文件否则工具连设备都识别不了。而当你手里只有一台分区表损坏的砖机时能救它的往往就剩一份完整备份的PGPT和一台能跑Python的电脑。这篇文章我想把整个流程完整写出来从获取MTK设备上的PGPT原始数据开始到用Python解析分区表结构再到自动生成可被SP Flash Tool识别的线刷引导文件。不是那种只给你一段模糊思路的科普文而是你照着操作就能出结果、遇到报错也能自己排查的保姆级实战记录。适用于手机维修从业者、ROM定制爱好者也包括单纯想学会Python二进制文件解析的新手只要有耐心都能跟完这一整条链路。全文没用什么高深理论核心就一个思路GPT分区表是固定格式的二进制数据Python能把这段二进制翻译成人话再反过来生成刷机工具需要的文本配置。1. 为什么MTK刷机要先搞定PGPT分区表很多人第一次看到“PGPT”这三个字母都是一脸懵。其实它就是把GPT分区表原封不动存成一个分区名字就叫pgpt。MTK平台的存储设备eMMC或UFS在出厂时被划分为几十个区域每个区域的起始地址、大小、用途都记录在分区表里。对于刷机来说线刷工具需要知道“哪个分区对应哪个镜像文件”“这个分区的物理地址是多少”这些信息不会凭空出现都要靠scatter文件提供而scatter文件的源头就在PGPT里。1.1 GPT结构手机存储里的目录和书签可以把整块手机存储想象成一本厚厚的书书的目录就是GPT分区表。数据是正文正文可以重新写但目录如果丢了、乱了整本书就再也翻不明白了。GPT分区表在磁盘上有两份一份叫Primary GPT主分区表也就是我们说的PGPT一份叫Secondary GPT备份分区表简称SGPT两份互为保险。MTK平台把PGPT单独做成了一个分区分区名就叫pgpt后面紧跟着sgpt。这也是为什么MTK设备的scatter文件里总能看到这两个分区名的原因。从存储的最开头数起第0号逻辑块LBA0放的是保护性MBR第1号逻辑块LBA1是GPT头里面记录着“分区表区域的起始位置”“分区条目个数”“CRC32校验值”等关键信息。从LBA2开始就是真正的分区条目数组每一条128字节记录一个分区的名称、起始逻辑块地址、结束逻辑块地址、类型GUID。MTK设备通常有几十个分区所以分区条目数组会连续占用好多个逻辑块。1.2 什么时候需要备份和重建PGPT备份PGPT这件事很多人觉得多此一举直到变砖了才后悔。我刚入行的时候也一样拿到一台MT6765的设备手贱点了“Format All”格式化过程走一半断电了再开机直接黑屏连SP Flash Tool都提示找不到设备。后来折腾了快两天才意识到是因为分区表被清掉线刷工具连怎么划分存储都不知道了自然也就识别不了设备。需要做PGPT备份和scatter生成的场景其实很明确救砖设备分区表被破坏或者被低格工具搞乱了需要靠完整的分区表数据恢复存储布局。定制ROM要在原厂分区基础上调整大小、增加新分区或者替换系统分区就必须先搞清楚现有分区表长什么样。备份固件在给客户设备做维修前先备份一份完整分区表万一操作失误还能退回原状。缺少scatter的刷机包手里只有一个线刷包但没带scatter文件或者scatter文件与设备不匹配这时候就需要自己从设备里读出分区表再生成一个。为什么这里非要用Python因为手工用十六进制编辑器去翻二进制遇到几十个分区根本翻不过来。我以前用HxD逐个对照偏移量光解析一个分区表就花了半小时中间还容易看错字节偏移。用Python脚本一次解析几十个分区两秒钟全部打印出来还能直接生成scatter文件这才是能长期用的方案。2. 准备工作先拿到设备上的PGPT原始数据要解析PGPT第一步得先把这份二进制数据从手机里“掏”出来。这一步卡住了很多人因为不同的设备进刷机模式的方式不同工具版本也五花八门。我建议把几种主流方式都学会哪个能用就用哪个毕竟在实际维修现场手段越多越好。2.1 环境准备Windows加Python的最小配置后面所有脚本都基于Python 3建议装Python 3.8以上版本。安装的时候有个容易忽略的点在安装向导第一步一定要勾选“Add Python to PATH”否则后面在cmd里敲python会提示找不到命令。如果你已经装过了但没勾选也可以手动把Python安装目录和Scripts目录加到环境变量里网上相关教程很多这里不展开。装好之后打开命令提示符敲一下python --version能打印出版本号就说明环境没问题。然后顺手把后面要用的mtkclient装上这个工具是用Python写的MTK刷机辅助程序后面会用到pip install mtkclientPython环境够用即可不需要装什么重量级IDE。VS Code加Python插件就很好用能直接运行脚本也能看报错信息。要是你只是想把脚本拿来直接用连编辑器都可以省了把代码保存成.py文件命令行运行就行。2.2 让手机进BROM模式MTK设备刷机依赖“BROM模式”这是芯片BootROM里的一个底层下载模式。手机断电之后插入USB数据线系统会自动进入这个模式这时电脑端的设备管理器里能看到一个“MediaTek USB Port”之类的COM口设备。不同机型的触发方式有差别最常见的是关机之后按住“音量上”或“音量下”键不松手再插入数据线。我自己接触过的机器红米的MTK机型一般按音量下部分老MT6589的机器要按音量上还有些平板设备需要短接主板上标好的测试点才能进BROM。实在试不出来的话可以试试“闹钟法”在正常开机的系统里设置一个一分钟后的闹钟让它自动重启进BROM这个方法对某些老机型很管用。进模式之后不要急着进行下一步先到设备管理器里确认驱动有没有装好。win10和win11系统大部分情况能免驱识别要是看到带黄色感叹号的设备就手动装一下MTK USB VCOM驱动否则后面工具连接会报错。2.3 方法A用SP Flash Tool导出一份PGPTSP Flash Tool是MTK官方线刷工具大家常叫它“一线工具”。除了刷机它的Read Back功能也能用来读设备数据。打开工具后先加载Download Agent也就是DA文件。DA文件一般在官方刷机包里能找到后缀是bin在刷机包的DA文件夹里。切到Read Back页签点“Add”添加一个读取任务。这里的关键是地址和长度两个参数起始地址填0x0长度我习惯填0x4000也就是从存储最开头连续读16KB。这个长度已经覆盖了GPT头加分区条目数组再往后还包含了备份分区表的一部分足够后续解析用了。设备进入BROM模式并连接电脑后点击Read Back按钮工具会列出可用COM口选对端口开始读取。等进度条走到100%保存成PGPT.bin一份原始的PGPT数据就到手了。实际操作中如果SP Flash Tool版本较老Read Back页签可能会让填“起始扇区”而不是“起始地址”原理是一样的还是从0开始。2.4 方法B用mtkclient命令行读取SP Flash Tool读分区表有个前提需要有匹配的DA文件。要是找不到DA或者DA版本不匹配就会一直卡在“连接设备”这一步。这时候第二套方案就很有用了——用mtkclient从BROM层面直接读取它不需要额外的DA文件很多情况下比SP Flash Tool还省事。环境准备好之后把手机正常开机状态关掉插好USB线进入BROM模式然后在命令行执行python mtk.py r pgpt PGPT.binmtkclient会自动识别设备并建立连接然后把名为pgpt的分区内容读取到本地文件。如果你的设备固件比较特殊分区名不是标准的pgpt也可以直接按硬件地址读取存储最开头的16KBpython mtk.py r --lun 0 --part 0 --start 0 --length 0x4000 PGPT.bin不同环境下mtkclient的具体参数会有细微差别读取之前先在当前目录执行python mtk.py --help看一下帮助信息确认一下子命令和参数格式。我自己用的时候就遇到过旧版mtkclient不支持--lun参数的情况换成分区名读取反而顺利。2.5 校验备份文件的完整性不管用哪种方式拿到文件之后第一件事是检查数据是否完整。用十六进制编辑器打开PGPT.bin最前面的字节应该是00 00 00 00保护MBR滚动到文件偏移0x200处如果能看到45 46 49 20 50 41 52 54这几个字符翻译过来就是“EFI PART”说明GPT头是完整的文件基本没问题。如果文件开头直接裸奔着一堆混乱字节或者GPT头区域全是FF大概率是读取地址不对或者设备压根没处于BROM模式。这时候别急着往下走先回头确认读取过程有没有报错。还要检查文件大小是不是足够的我上面建议读16KB如果只读了一个扇区512字节就停了那只有GPT头没有分区条目后面的脚本一样跑不通。3. 核心用Python解析PGPT二进制数据拿到原始数据之后接下来就是重头戏。解析PGPT这个过程本质上就是按照GPT规范把二进制字段翻译成人类能看懂的表格。这个规范是公开的不针对MTK所以搞明白一次以后任何用GPT分区表的设备都能用同样的方法处理。3.1 GPT分区表格式拆解偏移量决定一切二进制解析最怕的就是“不知道这段数据代表什么”。GPT头从文件偏移0x200开始长度固定为92字节。我整理了一个最常用的偏移表照着这个表就能把关键字段全部读出来偏移长度字段含义0x008字节签名固定为“EFI PART”0x104字节头部CRC32校验值0x388字节分区条目区域起始LBA通常为20x504字节分区条目个数通常为1280x544字节单个分区条目大小通常为128字节再往下看分区条目区域从起始LBA乘以扇区大小得到文件偏移。MTK的eMMC设备扇区大小通常是512字节所以分区条目区域一般在文件偏移0x400处。每一条分区条目是128字节结构也有固定规范条目内偏移长度字段含义0x0016字节分区类型GUID0x1016字节分区唯一GUID0x208字节分区起始LBAuint640x288字节分区结束LBAuint640x3872字节分区名称UTF-16LE编码理解这个结构是后面所有脚本的灵魂。其实编程工作就三件事定位偏移、按类型解析字节、把结果格式化输出。3.2 编写解析脚本从二进制到分区列表我直接给出一个可以运行的Python脚本保存为parse_pgpt.py用的时候把文件路径当参数传进去就行。import struct import zlib import sys SECTOR_SIZE 512 def parse_guid(data: bytes) - str: g1 struct.unpack(I, data[0:4])[0] g2 struct.unpack(H, data[4:6])[0] g3 struct.unpack(H, data[6:8])[0] g4 data[8:10].hex().upper() g5 data[10:16].hex().upper() return f{g1:08X}-{g2:04X}-{g3:04X}-{g4}-{g5} def read_partition_name(raw: bytes) - str: name raw.decode(utf-16-le, errorsignore) return name.split(\x00)[0] def parse_gpt_file(file_path: str): with open(file_path, rb) as f: data f.read() gpt_offset SECTOR_SIZE if data[gpt_offset:gpt_offset 8] ! bEFI PART: print([-] 未找到有效的GPT头请确认文件是从LBA0开始读取的完整镜像。) return header data[gpt_offset:gpt_offset 92] if len(header) 92: print([-] GPT头不完整文件长度不足。) return stored_crc struct.unpack(I, header[0x10:0x14])[0] calc_crc zlib.crc32(header[:0x10] b\x00\x00\x00\x00 header[0x14:]) 0xFFFFFFFF print(f[i] 头部CRC存储值0x{stored_crc:08X} 计算值0x{calc_crc:08X}) parts_lba struct.unpack(Q, header[0x38:0x40])[0] num_parts struct.unpack(I, header[0x50:0x54])[0] part_size struct.unpack(I, header[0x54:0x58])[0] entries_offset parts_lba * SECTOR_SIZE print(f[i] 分区条目起始LBA{parts_lba}, 分区条目个数{num_parts}, 条目大小{part_size}) print(- * 100) for i in range(num_parts): start entries_offset i * part_size entry data[start:start part_size] if len(entry) part_size: break part_type parse_guid(entry[0:16]) prev_lba struct.unpack(Q, entry[0x20:0x28])[0] last_lba struct.unpack(Q, entry[0x28:0x30])[0] name read_partition_name(entry[0x38:0x80]) if name and prev_lba 0 and last_lba 0: continue start_addr prev_lba * SECTOR_SIZE end_addr (last_lba 1) * SECTOR_SIZE size_mb (last_lba - prev_lba 1) * SECTOR_SIZE / (1024 * 1024) print(f{i:3d} {name:32} start0x{start_addr:012X} fend0x{end_addr:012X} size{size_mb:10.2f} MB {part_type}) print(- * 100) print(f[] 完成共解析到 {num_parts} 个分区条目。) if __name__ __main__: if len(sys.argv) 2: print(f用法: python {sys.argv[0]} PGPT文件路径) sys.exit(1) parse_gpt_file(sys.argv[1])运行方式特别简单python parse_pgpt.py PGPT.bin脚本正常运行时会先把GPT头的CRC校验结果列出来再按顺序打印每个分区的序号、名称、起始物理地址、结束物理地址和大小。你可以拿这个结果和官方scatter文件做对比只要对应分区的起始地址一致就说明解析逻辑没问题。3.3 CRC校验失败代表什么很多人在解析时看到“头部CRC存储值0xFFFFFFFF 计算值0x12345678”这样的输出心里就发毛担心是不是脚本坏了。其实这恰恰是脚本在帮你发现备份数据的问题。GPT头的CRC32字段记录的是一个校验值计算公式是把该字段本身置零后对整个头部做CRC32。如果磁盘上的数据没有被破坏存储值应该等于计算值两者一致代表这92个字节没有被动过。如果不一致说明PGPT数据本身已经损坏或者备份的时候没有从一个完整且未被改写过的存储区域读取。遇到CRC不一致先别急着用这个数据生成scatter。可以尝试读取设备的SGPT备份分区用备份分区表交叉验证。MTK平台一般把sgpt分区放在存储的后面如果设备还能正常进系统也可以用固件提取工具直接从系统里抠出完整的分区表文件。我之前遇到过一台设备用户用第三方工具乱改过分区大小导致PGPT和SGPT不一致解析出来甚至会出现某些分区起始地址和官方版本明显对不上这种情况就要谨慎处理。3.4 怎么确认解析结果可信判断解析结果对不对有个最笨但最有效的办法和官方线刷包里的scatter文件对比。官方刷机包里通常自带一个scatter你用文本编辑器打开它对照里面的linear_start_addr字段再看脚本输出里对应分区的start地址两者应该完全一致。还有几个特定分区可以作为“锚点”preloader的起始地址在多数平台上是0x0pgpt分区通常在存储开头附近nvram、protect1、protect2这几个特殊分区的地址在不同平台上差异很大不用死记只需要确认脚本输出的地址在合理的物理范围内即可。如果上面说的锚点分区一个都找不到打印出来的分区名也完全不是MTK平台常见的名字那基本可以断定读错位置了。最常见的原因是文件不是从LBA0开始读取的而是从GPT分区条目区域开始读取或者是从某个分区的中间读的重新用SP Flash Tool或mtkclient读出完整数据就好。4. 从解析结果生成可用的scatter引导文件解析PGPT只是前半程真正让人头疼的是生成scatter。MTK的线刷工具对scatter文件格式要求非常严格一个标点不对工具就会提示“Format scatter file fail”逼得很多人只能手动改官方的scatter凑合着用。手动改一两个分区还行要是整个分区表都要重排非得写脚本不可。4.1 先搞清楚scatter文件的格式不同版本的SP Flash Tool对scatter文件的支持有差异新版本工具能兼容旧的scatter文件反过来就不好说了。这里我以目前最常用的V5/V6格式为例它的分区条目长这样platform: MT6765 storage: EMMC - partition_index: SYS0 partition_name: preloader file_name: preloader.bin is_download: true type: SV5_BL_BIN linear_start_addr: 0x0 partition_size: 0x400000 region: EMMC_BOOT_1文件开头两行是平台信息。platform字段要填芯片型号比如MT6765、MT6785、MT6833这些storage字段填存储类型eMMC设备填EMMCUFS设备填UFS。这个信息不需要从分区表里解析需要你根据设备硬件自己填。每个分区条目里partition_index从SYS0开始依次递增partition_name是分区名必须和擦除镜像时的分区名一致file_name是实际要刷入的镜像文件名一般默认和分区名相同is_download控制SP Flash Tool刷机时是否勾选该分区true表示勾选false表示不勾选type是分区类型这个字段对刷机工具判断镜像的加载方式很重要linear_start_addr就是我们在3.2中计算出的起始物理地址partition_size是分区大小region指定分区所在存储区域EMMC平台通常有EMMC_BOOT_1、EMMC_BOOT_2和EMMC_USER三个区域。新手最容易犯错的地方是抄了一个网上的老模板把type字段填得五花八门或者漏了region字段。轻则工具提示格式错误重则刷机能识别但刷写时把数据写到了错误的存储区域。4.2 Python批量生成scatter规则与模板生成scatter其实就是在做字符串拼接但拼接之前要先处理几条经验规则分区名是preloader的分区type固定为SV5_BL_BINregion固定为EMMC_BOOT_1。分区名是boot1、boot2的分区region分别对应EMMC_BOOT_1和EMMC_BOOT_2type填EMMC_BOOT_1或EMMC_BOOT_2。分区名是nvram、nvdata、protect1、protect2这种包含用户信息的分区建议把is_download设为false防止误刷导致IMEI丢失或WIFI地址异常。其他普通用户区分区type填NORMAL_ROMregion填EMMC_USER。UFS设备的region要换成UFS_LUN0、UFS_LUN1等不同芯片对UFS LUN的分区编号不一样最好结合官方scatter确认。下面这个脚本可以在你的电脑上直接运行它会读取解析脚本输出的分区列表并自动生成scatter文件import struct import zlib import sys SECTOR_SIZE 512 DEFAULT_REGION EMMC_USER SPECIAL_TYPES { preloader: (SV5_BL_BIN, EMMC_BOOT_1), boot1: (EMMC_BOOT_1, EMMC_BOOT_1), boot2: (EMMC_BOOT_2, EMMC_BOOT_2), } NO_DOWNLOAD_PARTS { nvram, nvdata, protect1, protect2, seccfg, md1img } def parse_gpt_parts(file_path: str): with open(file_path, rb) as f: data f.read() gpt_offset SECTOR_SIZE header data[gpt_offset:gpt_offset 92] parts_lba struct.unpack(Q, header[0x38:0x40])[0] num_parts struct.unpack(I, header[0x50:0x54])[0] part_size struct.unpack(I, header[0x54:0x58])[0] entries_offset parts_lba * SECTOR_SIZE parts [] for i in range(num_parts): entry data[entries_offset i * part_size: entries_offset (i 1) * part_size] if len(entry) part_size: break name_raw entry[0x38:0x80].decode(utf-16-le, errorsignore) name name_raw.split(\x00)[0] start_lba struct.unpack(Q, entry[0x20:0x28])[0] last_lba struct.unpack(Q, entry[0x28:0x30])[0] if name and start_lba 0 and last_lba 0: continue parts.append({ name: name, linear_start_addr: start_lba * SECTOR_SIZE, partition_size: (last_lba - start_lba 1) * SECTOR_SIZE, }) return parts def generate_scatter(parts, platformMT6765, storageEMMC): lines [] lines.append(fplatform: {platform}) lines.append(fstorage: {storage}) lines.append() for idx, part in enumerate(parts): name part[name] if name in SPECIAL_TYPES: part_type, region SPECIAL_TYPES[name] else: part_type NORMAL_ROM region DEFAULT_REGION is_download false if name in NO_DOWNLOAD_PARTS else true lines.append(f- partition_index: SYS{idx}) lines.append(f partition_name: {name}) lines.append(f file_name: {name}.bin) lines.append(f is_download: {is_download}) lines.append(f type: {part_type}) lines.append(f linear_start_addr: 0x{part[linear_start_addr]:X}) lines.append(f partition_size: 0x{part[partition_size]:X}) lines.append(f region: {region}) lines.append() return \n.join(lines) if __name__ __main__: if len(sys.argv) 2: print(f用法: python {sys.argv[0]} PGPT文件路径 [platform] [storage]) sys.exit(1) pgpt_path sys.argv[1] platform sys.argv[2] if len(sys.argv) 2 else input(请输入平台型号例如MT6765: ).strip() storage sys.argv[3] if len(sys.argv) 3 else input(请输入存储类型EMMC或UFS: ).strip() parts parse_gpt_parts(pgpt_path) scatter generate_scatter(parts, platform, storage) output_path f{platform}_auto.scatter with open(output_path, w, encodingascii, newline\n) as f: f.write(scatter) print(f[] scatter文件已生成: {output_path}) print(f[] 共生成 {len(parts)} 个分区条目。)运行方式python gen_scatter.py PGPT.bin MT6765 EMMC脚本会把生成的scatter文件保存为MT6765_auto.scatter。打开看一下分区顺序和PGPT里的顺序一致地址也都是从0x0开始的连续地址。如果某个分区类型判断得不对比如你的设备preloader分区名字叫preloader_a而不是preloader你可以改一下代码里的SPECIAL_TYPES字典把实际分区名加进去。4.3 落地验证把生成的scatter灌进SP Flash Tool生成scatter只是纸上谈兵真正行不行还要让SP Flash Tool认一次。把生成的.scatter文件和对应镜像放到同一个目录下打开工具点“Choose”选择这个文件工具会解析并显示出所有分区列表。这时候可以做个快速检查工具显示的每个分区是否按顺序排列地址是否连续有没有出现地址重复或者明显跳变。如果工具直接弹窗报错“Format scatter file fail”大概率是文件里有非法字符最常见的原因是用记事本保存时把编码改成了UTF-8带BOM或者文件末尾多了一个不可见符号。解决方案是用VS Code或Notepad把文件转为ASCII编码再保存一次。验证通过之后建议不要一上来就全选Download。我这里有个习惯先只勾选preloader这一个分区执行一次Download确认设备能被正常识别、刷写过程和地址都是对的然后再全选执行完整线刷。这个方法能帮你把风险控制到最低要是preloader都能正常刷进去剩下的普通用户分区出问题的概率就很小了。5. 实操中常见问题与排查技巧实录写代码、生成文件、连设备每一步都可能踩坑。我把这些年实操过程中遇到的高频问题整理成一个速查表方便你对照处理。5.1 问题排查速查表现象可能原因解决办法脚本提示“未找到有效的GPT头”读取起始位置不对文件不是从LBA0开始用SP Flash Tool的Read Back重新从0x0地址读取头部CRC校验失败PGPT数据损坏或备份时被工具改动过读取SGPT备份交叉验证确认数据来源可靠解析出来的分区名全是乱码编码识别错误工具存成了其他编码检查文件是否被文本编辑器动过坚持用二进制读取scatter载入报“Format scatter file fail”编码不是ASCII或字段拼写错误用VS Code转成ASCII编码对照官方scatter检查字段preloader地址对不上平台特殊GPT条目的起始地址不是0手动修正特殊分区的起始地址参考官方scatter设备无法进入BROM模式驱动没装好或触发方式不对设备管理器确认COM口更换数据线尝试短接测试点5.2 几个容易踩的坑第一mtkclient和SP Flash Tool不能同时打开。这两个工具在连接BROM设备时会争抢同一个COM口我见过最诡异的情况就是在SP Flash Tool还在运行的时候启动了mtkclient然后两个工具都提示设备离线。刷机不需要同时开两套工具先关掉另一个再连设备。第二地址换算一定要搞清扇区大小。eMMC存储的扇区大小一般是512字节但UFS存储的扇区大小可能是4096字节。GPT头里的parts_lba是逻辑块号换算成文件偏移时必须乘上正确的扇区大小。我之前给一台UFS平板生成scatter用512去乘结果所有地址都偏了盯着看了半天也没发现问题来源最后是拿官方scatter一对比才醒悟。第三preloader的地址不能光看GPT的起始LBA。很多MTK平台的preloader实际跑在英特尔的bootrom映射区GPT里记录的起始LBA可能是0x0也可能是一个特殊偏移。生成的scatter如果不被工具接受试着查看官方scatter是怎么定义preloader的直接照抄。第四从PGPT恢复分区表时不能只把PGPT写回LBA0。GPT规范要求磁盘末尾还要有备份分区表SGPT许多刷机工具在下载前会先校验主备份分区表的一致性只恢复一半很容易刷到一半又报错。安全做法是用十六进制编辑器同时把PGPT和SGPT区域都写回这个操作要在设备能进入底层模式的前提下做否则很可能越弄越糟。5.3 进阶扩展顺手做一个小工具既然已经有了解析和生成两段脚本稍微改改就能变成一个更顺手的小工具。我后来把两个脚本合并成了一个每次打开时先弹出文件选择对话框选中PGPT文件后自动解析再弹窗让填平台型号和存储类型一键生成scatter。整个过程不用敲命令行给同行用也很方便。再进一步你还能把脚本改造成一个MTK刷机包校验工具加载官方scatter文件把里面每个分区的file_name和实际目录里的镜像文件做对应检查是不是漏了镜像、镜像文件名是不是错了。这些功能本质上都是对文本和二进制做处理Python的灵活性在这里发挥得淋漓尽致。写在最后我在实际维修中最大的感触是PGPT这份数据平时看起来只是一个藏在设备深处的二进制文件但在关键时刻它决定了一台砖机是能复活还是彻底报废。每次拿到新设备刷机之前我都会顺手备份一下PGPT和SGPT几秒钟的事却能省下后面几十个小时的折腾。最后再分享一个小技巧备份出来的PGPT文件除了原始.bin文件我还会把它压缩一份留底同时记录文件的SHA256值。等到哪天不小心改了分区表或者准备恢复的时候能通过哈希值检查这份备份有没有被意外改动过。技术这行习惯做得越细现场翻车的概率就越低。