定长文件接口的解析与对账
目标
按照布局解析定长报文文件,使用尾记录验证完整性,并完成编码转换、完成标志、归档和核对,走完文件接口的一个完整周期。
为什么重要
文件集成看似陈旧,但在批量处理和可核对性方面仍然是最佳选择。问题在于,它的失败方式往往悄无声息。如果直接处理传输中被截断的文件,系统可能不报错却只应用一半数据,直到月末结算时才以“数字对不上”的形式暴露。如果完成标志约定只在一端实现,批处理可能每天什么也不处理,却不产生任何错误。**悄然什么都不做,往往最晚才被发现。**尾记录验证和核对正是让这种静默失败发出声响的机制。
步骤
- 阅读
/opt/lab/fixtures/eai/file/layout.md,创建/root/f/layout.csv。 第一行为seq,field,start,length,type。start是从 1 开始的位置,按seq顺序排序。 - 创建
/root/f/parse.sh。接收一个参数(数据文件),只输出以 D 开头的数据记录,并用管道符(|)分隔以下 6 个字段。
删除字符字段首尾的空格,并删除数值字段开头的 0。 (不输出SALE_DT|CUST_ID|CUST_NM|PROD_CD|QTY|AMTREC_TYPE。) 使用/opt/lab/fixtures/eai/file/SALES_20260801.dat运行,并将结果保存到/root/f/parsed.txt。 - 创建
/root/f/verify.sh。接收一个参数(数据文件);如果尾记录中的记录数和金额合计与数据记录一致,则以退出码 0 结束;如果不一致,则在第一行输出原因,并以非 0 退出码结束。SALES_20260801.dat→ 必须通过SALES_20260802.dat→ 必须失败
- 将
/opt/lab/fixtures/eai/file/SALES_EUCKR.dat转换为 UTF-8,并保存到/root/f/SALES_utf8.dat。转换后韩文必须能够正常读取。 - 创建
/root/f/pick.sh。接收一个参数(目录),每行仅输出一个同时存在.ok标志文件的.dat文件名。不得输出.ok文件本身。 - 创建
/root/f/csvcheck.py。接收一个参数(CSV 文件),输出一行rows=<데이터 행수> fields=<헤더 필드수> bad=<필드수가 다른 행수>。必须正确处理引号内的逗号和换行。使用/opt/lab/fixtures/eai/file/orders_quoted.csv运行,并把结果保存到/root/f/csvcheck.txt。 - 将
SALES_20260801.dat以 gzip 压缩方式归档到/root/f/archive/20260801/下。文件名必须是在原文件名后添加.gz。 - 创建
/root/f/recon.csv。第一行为item,source,target,diff,result。比较/opt/lab/fixtures/eai/file/SALES_20260801.dat(source)与/opt/lab/fixtures/eai/file/SALES_20260801.csv(target),填写count和amount两行。result一致时为OK,不一致时为NG。
参考
- 按字节截取:
cut -b 1-8,按字符截取:cut -c 1-8 - 编码转换:
iconv -f EUC-KR -t UTF-8 입력 > 출력 - 删除开头的 0:
$((10#$값))或sed 's/^0*//'(全部为 0 时注意结果为空字符串) - 解析 CSV 请使用 Python 的
csv模块。自行拆分会在处理引号时出错。 - 常见错误 1:把头记录(H)和尾记录(T)计为数据。
- 常见错误 2:对含有韩文的字段按字符截取,导致位置偏移。
- 常见错误 3:把
.ok文件本身列入处理对象。
整理布局定义
阅读 /opt/lab/fixtures/eai/file/layout.md,创建 /root/f/layout.csv。
第一行为 seq,field,start,length,type。
start 是从 1 开始的位置,按 seq 顺序排序。
起始位置从 1 开始计数。前面各字段的长度之和再加 1,就是下一个字段的起始位置。请验算最后一个字段的结束位置是否与整条记录的长度一致。
定长解析器
创建 /root/f/parse.sh。接收一个参数(数据文件),只输出以 D 开头的数据记录,并用管道符(|)分隔以下 6 个字段。
SALE_DT|CUST_ID|CUST_NM|PROD_CD|QTY|AMT
删除字符字段首尾的空格,并删除数值字段开头的 0。
(不输出 REC_TYPE。)
使用 /opt/lab/fixtures/eai/file/SALES_20260801.dat 运行,并将结果保存到 /root/f/parsed.txt。
cut 的 -b 按字节处理,-c 按字符处理。混有韩文时,这一区别会改变结果。还需要确定如何处理数值字段开头的 0。
验证尾记录
创建 /root/f/verify.sh。接收一个参数(数据文件);如果尾记录中的记录数和金额合计与数据记录一致,则以退出码 0 结束;如果不一致,则在第一行输出原因,并以非 0 退出码结束。
SALES_20260801.dat→ 必须通过SALES_20260802.dat→ 必须失败
必须在处理前进行验证。如果在处理中验证,可能已有一半数据被应用。记录数和合计值都必须检查。
转换编码
将 /opt/lab/fixtures/eai/file/SALES_EUCKR.dat 转换为 UTF-8,并保存到 /root/f/SALES_utf8.dat。转换后韩文必须能够正常读取。
收到的文件显示乱码时,应先怀疑编码问题。在韩国国内的外部系统集成中,仍在使用韩文占 2 字节的编码。
筛选完成标志
创建 /root/f/pick.sh。接收一个参数(目录),每行仅输出一个同时存在 .ok 标志文件的 .dat 文件名。不得输出 .ok 文件本身。
没有标志的文件可能仍在传输中。让脚本接收目录参数,并且只输出处理对象。
验证 CSV 接口
创建 /root/f/csvcheck.py。接收一个参数(CSV 文件),输出一行 rows=<데이터 행수> fields=<헤더 필드수> bad=<필드수가 다른 행수>。必须正确处理引号内的逗号和换行。使用 /opt/lab/fixtures/eai/file/orders_quoted.csv 运行,并把结果保存到 /root/f/csvcheck.txt。
CSV 的引号内可以包含逗号和换行。简单拆分会得到错误的字段数。请使用标准解析器。
处理后归档
将 SALES_20260801.dat 以 gzip 压缩方式归档到 /root/f/archive/20260801/ 下。文件名必须是在原文件名后添加 .gz。
按日期划分目录,可以避免一个目录堆积数十万个文件。文本的压缩效果很好。
编制核对表
创建 /root/f/recon.csv。第一行为 item,source,target,diff,result。比较 /opt/lab/fixtures/eai/file/SALES_20260801.dat(source)与 /opt/lab/fixtures/eai/file/SALES_20260801.csv(target),填写 count 和 amount 两行。result 一致时为 OK,不一致时为 NG。
只要记录数相同就容易掉以轻心,但如果一条遗漏、另一条重复,记录数仍然相同。因此还要同时检查合计值。