
简介东京游戏展2011主题资源包面向游戏爱好者、怀旧玩家与游戏数据研究者旨在运行和回顾展会相关的模拟程序及互动内容。这个rar压缩包共六百六十五个文件、整体仅约四点五MB主要包含smp与sdb数据文件、html页面、txt说明、lua脚本及exe执行程序其中smp与sdb用于核心数据存储html提供界面展示txt承载文档说明lua负责功能触发。截至目前已有七百零九人学习下载。包内提供主程序、更新记录、使用说明以及设定和清除装备强化属性、修改角色年龄等脚本文件并带有以‘太极’命名的版本标识。借助这些内容读者可了解游戏机制、查阅迭代记录通过年龄调整等功能获得差异化的展会体验也可作为研究早期游戏数据结构的参考样例若对游戏版本演化感兴趣还可借此梳理不同迭代间的差异。1. 拆开 TGS2011 时间戳压缩包这不是一次简单的“解压”我接手这批数据时文件名是tgs2011 (20171226).rar、TGS2011 20180428、TGS2011-2107-12-一眼扫过去像乱码细看全是时间戳。TGS2011 是某区域 2011 年基线测绘数据集的代号项目组按季度发布快照于是同一份数据在一年里产出了多个带时间戳的归档版本。老工程师习惯把这类数据直接用 RAR 分卷打包因为单卷就能到 4GB 以上还能带恢复记录。这篇笔记就围绕这批带时间戳的归档来写怎么解开、怎么识别版本差异、怎么把散落的影像与标签对齐成能直接喂给模型的训练目录以及我踩过的那些分卷缺失、CRC 报错和编码乱码。如果你手上也有类似XXXX_YYYYMMDD.rar这种命名规则的历史数据这篇文章就是给你准备的。2. 数据分发方为什么偏爱 RAR分卷、恢复记录与跨平台解包2.1 RAR 分卷的内在结构为什么单卷压缩包容易翻车TGS2011 这套数据总大小约 62GB分发方在 Windows 环境用 WinRAR 切成了tgs2011.part01.rar到tgs2011.part13.rar。RAR 分卷和 ZIP 分卷最大的区别在于RAR 的分卷是强依赖的缺少任何一卷后续卷根本无法读取而 ZIP 分卷相对独立至少能解出完好部分。这既是保护机制也是坑位来源。RAR 还有一个 Z IP 很少见的功能叫“恢复记录”创建压缩包时如果勾选了rr5%或rr10%压缩包末尾会额外写入冗余数据。这个冗余数据的作用是当分卷出现局部损坏时允许工具尝试修复。对 60GB 级别的遥感数据来说网络传输中丢一个字节就可能导致整个分卷 CRC 失败而恢复记录就是分发方给接收方的一剂“后悔药”。我一般会用下面这条命令查看分卷里是否带恢复记录unrar l -v tgs2011.part01.rar | tail -20输出的末尾会明确标注Recovery record: Yes或No同时能看到每个分卷的Pack size与Unp size。如果恢复记录存在后续遇到单个坏块时可以用unrar r做修复这比重新下载几十 GB 的文件要省太多时间。2.2 Linux 下用 unrar 跑通第一个分卷解压在服务器上处理这种数据首选工具是unrar和p7zip-full。Debian/Ubuntu 系安装命令如下# 先安装基础工具Debian/Ubuntu sudo apt-get install unrar p7zip-full # 测试分卷完整性的正确姿势只测不修 unrar t tgs2011.part01.rar | tee tgs2011_test.log # 如果测试通过再执行解压 unrar x -o tgs2011.part01.rar ./tgs2011_extracted/这里有个关键点解压分卷只需要指定第一卷unrar会自动按编号寻找后续分卷。-o表示覆盖已有文件tee把测试日志留存下来方便和后续版本比对。如果测试阶段就报错千万不要跳过unrar t直接执行unrar x否则解压到一半突然中断留给你的是一堆不完整文件和一次毫无意义的磁盘 IO。参数的具体含义是t代表 test只读取分卷内容并计算 CRC不写任何文件x代表 extract保留完整目录结构。如果只想解压某个子目录可以在包名后面追加路径例如unrar x tgs2011.part01.rar ./tgs2011_extracted/raw/这样能避免把 60GB 全部摊开。2.3 Windows 与 Linux 之间的文件名编码差距如果你和我一样是在 Linux 服务器上跑解压大概率会遇到压缩包内文件名乱码的情况。原因是 RAR 打包端Windows默认使用 GBK 编码记录文件名而 Linux 系统默认 locale 是 UTF-8。这两者一旦对不上解压出来的目录名就会变成“锟斤拷”或者“锘挎櫤”这种天书。我常用的绕过方案是在解压时临时切换 locale# 用 GBK locale 解压跑完后恢复默认 locale LC_ALLzh_CN.GBK unrar x tgs2011.part01.rar ./tgs2011_extracted/如果系统里没有zh_CN.GBK需要先执行locale-gen zh_CN.GBK。解压完之后再用convmv批量把文件名转成 UTF-8convmv -f GBK -t UTF-8 -r --notest ./tgs2011_extracted/这个命令会递归重命名所有含非 ASCII 字符的文件与目录。注意那个--notest如果不加convmv 只打印将做什么而不实际改动适合先跑一遍确认范围。遇到批量文件更名时先 dry-run 是一个好习惯免得把原始归档的名字也一起改了。3. 拆包前先摸底只列不解压三张表看清 TGS2011 的家底3.1 用 unrar l 查看归档内容避免重复解压 60GB 数据面对体积不明的 RAR 分卷最忌讳的就是上来就解压。我习惯先用unrar l列目录只读取归档的索引信息IO 开销极小。命令如下unrar l -v tgs2011.part01.rar tgs2011_list.txt head -50 tgs2011_list.txt输出会分成左右两大部分左侧是文件名与目录路径右侧是压缩前大小、压缩后大小、日期时间、属性和 CRC32。通过这个文件清单你能在几分钟内判断出归档内部的目录结构。以 TGS2011 为例常见结构一般包含raw/、label/、meta/三个顶级目录raw放原始影像label放人工标注的矢量或栅格标签meta放每次采集的传感器参数与时间记录。基于以上信息可以整理出一张内部结构清单表顶层目录典型文件类型预计占比说明raw/.tif / .img / .bin70%原始波段数据未做几何校正label/.shp / .png / .json20%标签格式随版本迭代变化meta/.xml / .log / .txt10%含采集时间、云量、传感器编号有了这张表才算知道这套数据“能干什么”。如果只有影像没有标签那就得走预标注或者人工标注的流程如果标签齐全可以直接进入格式转换。3.2 对比 20171226 与 20180428 两个版本的文件差异同一项目的数据集经常存在多个发布时间点文件名里的20171226和20180428代表的是打包日期而不是数据采集日期。要判断两个版本之间到底改了什么最可靠的办法是对比归档内的文件清单。unrar lb tgs2011.part01.rar | sort list_20171226.txt # 假设另一个版本的归档叫 tgs2011_20180428.rar unrar lb tgs2011_20180428.rar | sort list_20180428.txt # 找出两个清单的差异 diff list_20171226.txt list_20180428.txtunrar lb是unrar l的极简模式只输出文件路径不打印大小和时间非常适合生成文件指纹。diff的结果会清晰展示哪些文件是新增的开头哪些被删除了开头。TGS2011 在 20180428 这个版本里最明显的差异是label/目录下新增了十几个.json文件而raw/目录完全没变。这说明数据方只修订了标注没有重新发布底层影像。在实际项目中我会把diff结果重定向到文件并交给下游算法同事确认因为标签格式变了训练脚本里的解析逻辑就必须同步调整否则模型会莫名读不到目标框。3.3 解析元数据文件从文件头推断传感器与采集时间TGS2011 的meta/目录下每个影像都对应一个同名.xml文件里面记录了传感器类型、成像时间和云覆盖率。如果直接打开 XML 人工阅读60GB 数据对应的几百个 XML 文件会耗费大量时间。我一般用 Python 批量解析提取关键字段生成索引表import xml.etree.ElementTree as ET import os, glob, csv meta_dir tgs2011_extracted/meta rows [] for xml_file in glob.glob(os.path.join(meta_dir, *.xml)): tree ET.parse(xml_file) root tree.getroot() # 字段名按实际 XML 结构调整 row { image_id: root.findtext(image_id, defaultunknown), acquisition_time: root.findtext(acquisition_time, default), cloud_percent: root.findtext(cloud_percent, default-1), sensor: root.findtext(sensor, defaultunknown), path: os.path.basename(xml_file) } rows.append(row) with open(tgs2011_meta.csv, w, newline) as f: writer csv.DictWriter(f, fieldnameslist(rows[0].keys())) writer.writeheader() writer.writerows(rows)这段代码读入所有 XML 文件提取四个核心字段并输出 CSV。findtext如果遇到字段缺失会返回默认值避免中间环节因为某个文件结构不完整而中断。拿到tgs2011_meta.csv之后你可以直接按云量排序优先把云量低于 10% 的样本挑出来参与模型训练采集时间字段则可以用于后续的时序切片。4. 把归档落成训练集目录重排、Manifest 生成与时间切片4.1 强制目录分层raw 与 processed 分离的标准布局解压出的原始目录通常层层嵌套而且命名风格不统一直接拿来做训练会让人头大。我会在项目根目录下重新规划一套标准布局mkdir -p /data/tgs2011/ mkdir -p /data/tgs2011/{raw,label,processed,manifest} mv tgs2011_extracted/raw /data/tgs2011/raw mv tgs2011_extracted/label /data/tgs2011/label mv tgs2011_extracted/meta /data/tgs2011/processed/meta这套布局定死了三个原则原始数据与处理结果分开标注与影像路径一一对应所有中间产物放在processed下。后续写训练脚本时只需要在配置里指定根目录为/data/tgs2011扫raw和label两个子目录即可。千万不要把解压出的原始目录直接混入训练集否则数据版本管理会变成一团乱麻。4.2 用 Python 批量为影像与标签建立对应清单Raster 影像数据集最常见的坑是影像文件名和标签文件名对不上。比如raw/IMG_0234.tif对应的标签可能是label/IMG_0234_label.png也可能是label/0234.png。我习惯写一段小脚本自动配对输出一个manifest.csv。import os, csv, re raw_dir /data/tgs2011/raw label_dir /data/tgs2011/label def extract_id(filename): # 提取文件名中的纯数字部分作为关联主键 match re.search(r(\d{4,}), os.path.basename(filename)) return match.group(1) if match else None manifest [] for raw_file in sorted(os.listdir(raw_dir)): if not raw_file.endswith(.tif): continue raw_id extract_id(raw_file) matched_label None for label_file in os.listdir(label_dir): if extract_id(label_file) raw_id: matched_label label_file break manifest.append({ raw_id: raw_id, raw_path: os.path.join(raw_dir, raw_file), label_path: os.path.join(label_dir, matched_label) if matched_label else , valid: matched_label is not None }) with open(/data/tgs2011/manifest/manifest.csv, w, newline) as f: writer csv.DictWriter(f, fieldnames[raw_id, raw_path, label_path, valid]) writer.writeheader() writer.writerows(manifest)这段脚本的核心在于extract_id函数它用正则提取文件名里的连续数字串作为关联键规避了前后缀不一致的问题。valid字段标记影像是否找到了对应标签下游脚本读取时可以直接filter掉validFalse的行。对于 TGS2011 这种情况大概率能配上九成以上剩下的手动补几个文件名即可。4.3 按 2017-12 时间切片划分训练/验证/测试集元数据里带有采集时间意味着可以按时间切片划分数据集避免随机划分导致的时间泄漏。TGS2011 的采集集中在 2017 年 10 月到 2018 年 3 月我按月份切把 12 月作为验证集主体其它月份作为训练集。import pandas as pd meta pd.read_csv(/data/tgs2011_meta.csv) meta[acquisition_time] pd.to_datetime(meta[acquisition_time]) train meta[meta[acquisition_time] 2017-12-01] val meta[(meta[acquisition_time] 2017-12-01) (meta[acquisition_time] 2018-01-01)] test meta[meta[acquisition_time] 2018-01-01] print(ftrain: {len(train)}, val: {len(val)}, test: {len(test)})这里没有使用 sklearn 的train_test_split而是硬性按月份切。原因是遥感数据在时间上具有强自相关性相邻月份的影像相似度极高随机划分会把同一个月的数据同时放进训练集和验证集导致验证指标虚高。按时间切分虽然会让训练集数量少一点但模型在跨时间预测上的表现更接近真实部署场景。如果你也处理带时间戳的数据建议先问自己一句模型上线后要预测的是“同一时期”还是“未来”答案决定切分方式。5. 避坑指南分卷缺失、CRC 错误与编码乱码的现场救火5.1 现象只解压出 30% 就报错原因是分卷缺失解压执行到三分之一终端突然输出Cannot find volume tgs2011.part05.rar然后整个进程退出。第一次遇到时我以为是命令写错了检查发现是分发方漏传了part05。这类情况在内部传输里并不少见FTP 同步时某个分卷被临时锁定导致漏传。解决方法是先重新拉取完整分卷列表再做一次完整性测试ls -la | grep tgs2011.part | wc -l unrar lb tgs2011.part01.rar | tail -5如果分卷数量对不上只能联系数据提供方补齐。有一个小技巧如果确实缺少中间某卷但你知道缺少的是哪一卷可以先尝试解压不依赖该卷的部分文件比如unrar x tgs2011.part01.rar ./out/raw/有时可以抢救出部分有用的目录。5.2 现象CRC 校验失败导致解压中断是下载损坏还是硬盘坏道解压时报错CRC failed in tgs2011.part07.rar文件被中断。常见原因有两个一是下载过程中网络波动导致字节错位二是磁盘扇区损坏。判断方法很简单重新对该分卷执行一次测试。unrar t tgs2011.part07.rar如果测试两次都报同样的 CRC 错误基本可以确定是文件本身损坏。此时先别急着重新下载看一眼分卷创建时是否设置了恢复记录unrar r tgs2011.part07.rarunrar r会用分卷内置的冗余数据尝试重建损坏的区块。TGS2011 这套数据我实际遇到过part09的 50KB 损坏执行unrar r后从part09修复出fixed.part09.rar后续解压完全正常。如果连恢复记录也没有那就老老实实重新下载该分卷别耗时间。5.3 现象解压后的文件目录出现“锟斤拷”乱码解压完成ls一看目录名变成锟斤拷2011锟斤拷。这是 Windows 打包的 RAR 在 Linux 下解压时的典型编码事故前面第 2.3 节提过。如果已经解压完了可以用convmv事后补救convmv -f GBK -t UTF-8 -r --notest /data/tgs2011/raw/注意convmv只能修复文件名不能修复文件内容里的编码问题。如果标签文件.json内部本身包含 GBK 编码的中文字段则需要用 Python 读入再转码with open(label.json, r, encodinggbk) as f: content f.read() with open(label_utf8.json, w, encodingutf-8) as f: f.write(content)我在 TGS2011 的标注文件里就遇到过这类情况一个多边形地块的名称字段是 GBK 编码直接用json.load会抛UnicodeDecodeError。转码后问题立刻消失。5.4 现象重解压后得到的二进制文件 MD5 全部对不上有次为了腾磁盘空间我删除了解压目录之后又从同样的 RAR 分卷重新解压结果发现raw/下的影像文件 MD5 和第一次解压时完全不一样。一开始以为数据损坏后来排查发现是第一次解压时某个分卷报过错但我用了-o忽略部分报错强行生成了一批不完整文件。第二次解压是在修复分卷之后执行的所以得到的是正确文件。这个坑告诉我要把解压过程中的日志留好。正确做法是时刻记住unrar t先于unrar x并且在执行解压后将日志存档unrar x tgs2011.part01.rar ./out/ 21 | tee tgs2011_extract_$(date %Y%m%d).log把每一步操作的日志命名成带当天日期后续无论是排查问题还是给同事交接都能快速定位到“是哪一次解压出了错”。如果依赖unrar t和unrar x两次校验文件名、大小、内容三层核对都能对上那基本可以放心进入训练流程。6. 让 TGS2011 这批历史数据“可复现”我留下的校验清单与目录快照数据整理到最后我会强制自己做两件事生成 SHA256 校验清单保存目录快照。这两件事可以确保未来任何时候回来看这套数据都能确认它有没有被动过手脚。# 为解压后的原始目录生成校验清单 find /data/tgs2011/raw -type f -print0 | xargs -0 sha256sum /data/tgs2011/manifest/raw_sha256.txt # 保存目录树快照 tree -L 2 /data/tgs2011 /data/tgs2011/manifest/tree_snapshot.txtsha256sum的输出包含文件完整路径与哈希值任何人拿到这份清单都能重新校验。tree -L 2则记录了目录结构遇到磁盘异常或误删文件时可以拿快照对比定位缺失项。对于 TGS2011 这种带时间戳的多版本数据我还会把三个版本的清单分别命名成v20171226.sha256、v20180428.sha256这样哪个版本对应哪份数据一目了然。如果你的团队有协作需求还可以写一个三行脚本把清单里的哈希值与远程对象存储上的校验值做对比但这个要看具体基础设施而定。回到 TGS2011 本身我最想分享的一个习惯是拿到任何历史压缩包先列目录、再测完整性、记录文件清单、最后才解压。这套流程花费的时间不会超过十分钟却能在后续几天甚至几周里省去大量排查时间。数据工程里最磨人的往往不是算法而是这些看得见摸得着的细节。希望这篇笔记能帮你少踩几个坑希望帮到你。本文还有配套的精品资源点击获取