一、简介

FFReader 提供完整的命令行模式(CLI),面向开发、运维与数据分析人员:一条命令即可将 OFD / CSV / FIXED / DBF 接口文件批量转换为 CSV / Excel / JSON / SQL,或对文件与目录做批量比对(diff),输出 Excel / JSON / HTML 差异报告。配合 --stdout 管道输出与 JSON 导出的 AI 解读元信息,可无缝衔接脚本、流水线与 AI 工具。

如需可视化的解析、阅读与编辑操作,请参阅FFReader使用手册

能力 说明
文件解析 自动识别 OFD / CSV / FIXED / DBF,一般情况下无需手动指定类型
导出格式 csv、xlsx(Excel)、json(含 AI 解析元信息)、sql(INSERT 或者REPLACE等语句)
文件比对 单文件或目录级批量 diff,输出差异报告为 Excel / JSON / HTML
批量处理 --batch 目录级批量转换与批量比对,支持 glob 过滤、排除、大小限制
标准输出 --stdout 将转换结果或 diffjson 直接输出到 stdout(便于管道/AI 分析)
配置匹配 自动按版本/字段数/行长匹配 INI 配置,支持 -p 手动指定。注意:CLI 暂不支持无配置的自动解析 CSV 文件(该能力仅 GUI 提供)——所有 CSV 配置均未命中时报 No CSV config matches this file,建议补全 config/ 下对应解析配置后使用
流式处理 大部分场景下csv/json/sql 导出逐块写出、内存占用量较低;对于不支持流式处理的xlsx 导出以及数据接口比对全量载入内存,此时可用 --max-size 限制文件大小

二、运行环境与可执行程序

各平台可执行程序

平台 CLI 模式使用的程序 说明
Windows FFReaderCli-x64.exe / FFReaderCli-x86.exe / FFReaderCli-ARM64.exe 专用命令行程序(原生控制台程序,stdout/stderr 分离,管道与重定向直接可用)。按系统架构选择对应文件
Linux FFReader-x86_64.AppImage / FFReader-aarch64.AppImage 单一程序同时支持 GUI 与 CLI(-c)模式
macOS FFReader.app/Contents/MacOS/FFReader 单一程序同时支持 GUI 与 CLI(-c)模式

注意:Windows 下的 FFReader-x64.exe / FFReader-x86.exe / FFReader-ARM64.exe 为 GUI 程序,不再支持 CLI 模式(传入 -c 等命令行参数时仅弹窗提示改用 FFReaderCli)。

Linux AppImage 启动失败说明:在部分 Linux 发行版(如麒麟 Kylin 等 FUSE 挂载不可用或不稳定的环境)上,直接运行 AppImage 可能启动失败,终端打印 execv error: Socket not connected(errno 107 ENOTCONN)。这是 AppImage type2 运行器(runtime)的报错——运行时先用 FUSE 把内部 squashfs 挂载到 /tmp/.mount_XXXexecv() 启动内部 AppRun,挂载通道失效时 execv() 失败即打印该错误,与 FFReader 程序本体、Qt 库均无关。遇到该错误时,请使用 AppImage 官方绕过 FUSE 挂载的参数 --appimage-extract-and-run 运行(解压到临时目录后直接运行,不依赖 FUSE):

./FFReader-x86_64.AppImage --appimage-extract-and-run -c -f input.txt -t csv -q 2
# 等价环境变量方式
export APPIMAGE_EXTRACT_AND_RUN=1 && ./FFReader-x86_64.AppImage -c -f input.txt -t csv -q 2

环境要求与配置目录

  1. Windows 系统按架构匹配:常规 64 位系统找 FFReaderCli-x64.exe,ARM 设备找 FFReaderCli-ARM64.exe
  2. Windows 系统下运行时,需保证可执行文件同级目录存在 config/ 配置目录(缺失时无法解析任何文件)。
  3. Linux 系统下,配置会在程序首次运行时自动解压存储到用户home目录下的 .ffreader/config/ 目录(缺失时无法解析任何文件)。如从未修改过该配置,升级 FFReader 后请删除此目录,程序运行时会自动解压新版本配置,或者使用一次GUI模式(此时会提示更新配置),如本地有修改配置,建议做好配置备份,以免升级时被误覆盖
  4. Windows 未找到 CLI 程序时,可从 www.ffreader.cn 下载包含命令行程序的完整版本。

三、快速上手

一个最简单的转换

# Linux / macOS:使用通用可执行程序,必须加 -c 进入 CLI 模式
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t csv -q 2

# Windows 使用专用CLI程序FFReaderCli 无需 -c
FFReaderCli-x64.exe -f OFD_XXX_XXX_20181016_04.TXT -t csv -q 2

执行后,会在源文件同目录生成 OFD_XXX_XXX_20181016_04.TXT.export.csv

查看帮助与版本

FFReader -h                  # 显示帮助信息
FFReader -c -v               # 显示版本和作者信息(Windows FFReaderCli 可直接 -v)

四、命令行基础与通用参数

命令格式

FFReader -c [必选参数] [可选参数]

通用参数

参数 说明
-c / --cli 启用 CLI 模式(Linux/macOS 单一程序下必须传递该参数,否则启动 GUI;Windows 独立命令行程序 FFReaderCli 无需此参数,传入亦被忽略)
-h / --help 显示帮助信息(单独使用 -h 也会进入 CLI 模式,无需 -c
-v / --version 显示程序版本和作者信息(Linux/macOS 需与 -c 搭配;Windows FFReaderCli 可直接使用)
-p <配置> / --config 指定解析配置,格式见第十一章
-o / --overwrite 目标文件已存在时强制覆盖
-O <路径> / --output 指定输出文件路径(可以是目录或具体文件路径;目录必须已存在,程序不会自动创建,指定具体文件路径时其父目录也必须已存在)
--stdout 结果输出到标准输出而非文件。支持:单文件转换 -t csv/json/sql、比对 -t diffjson(含批量比对);不支持 xlsxdiffxlsxdiffhtml(Excel/HTML 为文件格式,无法流式输出)。启用时 -o/-O 被忽略。注意:批量模式下 stdout 为逐文件 JSON 顺序拼接(多个 JSON 文档连排,非单一 JSON 文档),需流式解析;仅要单一汇总 JSON 需配合 --summary-only(仅批量比对支持);进度与错误信息始终走 stderr,stdout 仅承载转换数据,可安全用于管道
--batch 批量模式:处理目录下所有文件(不递归子目录),详见第七章
--max-size <大小> 文件大小限制:防止超大文件载入内存导致程序崩溃。支持 KB/MB/GB 单位(如 100MB),无单位按字节,-1 不限制(默认)。超限行为按模式区分(详见各模式章节):单文件导出报错退出(退出码 -1);批量导出跳过不导出;单文件/批量比对仅二进制比对、跳过接口比对,且diffjson 生成报告(标记 sizeExceeded=true,无字段定义/主键信息),diffhtml/diffxlsx 超限时无明细数据、不生成报告。csv/json/sql 导出为流式处理,该限制主要针对 xlsx 导出(数据全量载入内存)与比对模式(新旧文件均需载入内存)

五、文件转换(单文件导出)

基本用法

FFReader -c -f <文件路径> -t <csv|xlsx|json|sql> [可选参数]
参数 说明
-f <文件路径> / --file 待解析的源文件路径(必选)
-t <类型> / --type 导出目标类型:csv / xlsx / json / sql(必选)
--max-size <大小> 文件大小限制(见通用参数):超限文件直接报错退出(退出码 -1),不执行导出

输出文件命名规则(未用 -O 指定时): 与源文件同目录,文件名为 <源文件名(含原扩展名)>.export.<新扩展名>,如 OFD_XXX_XXX_20181016_04.TXT 导出 CSV 得到 OFD_XXX_XXX_20181016_04.TXT.export.csv

CSV 格式可选参数

参数 默认值 说明
-d <分隔符> / --delimiter , CSV 导出时的字段分隔符(1-10 个字符,不得包含换行、引号、反斜杠)
-q <1|2|3> / --quote-strategy 2(RFC4180) CSV 引号策略:1=不加引号 2=RFC4180按需 3=全部加引号。单文件 CSV 导出时必填(不传报错);批量模式下可选,默认 2

SQL 格式可选参数

参数 默认值 说明
-s <模板> / --sql-template SQL 模板,-t sql必须提供
-n / --null-empty 空字段输出裸 NULL(用于 SQL 导出)
-C <N> / --commit 0(不输出) 每 N 行插入一条 COMMIT;(N 取值 1-100000)

JSON 格式可选参数

参数 默认值 说明
--check-primary-key 检查并报告主键冲突信息(JSON 导出输出 primaryKeyConflict 段),所有行仍导出(含重复行),检测到冲突时退出码为 5。-t json 有效,其他导出格式(csv/xlsx/sql)忽略此参数
--ignore-warnings 抑制警告输出到 stderr,退出码返回正常值而非 5

六、文件比对(单文件 diff)

比对模式用于对比两个同类型文件,输出差异数据。

基本用法

FFReader -c -R <原文件> -N <新文件> -t <diffxlsx|diffjson|diffhtml> [可选参数]
参数 说明
-R <文件路径> / --orifile 原文件路径(必选)
-N <文件路径> / --newfile 新文件路径(必选)
-t <类型> / --type 导出类型(必选):diffxlsx(差异 Excel)/ diffjson(差异 JSON)/ diffhtml(差异 HTML 可视化报告)

比对可选参数

参数 默认值 说明
--diff-single-side 比对单边字段(一方存在另一方不存在的字段视为差异)
--ignore-fields <字段列表> 忽略比对的字段(逗号分隔,支持英文名或中文描述)
--force-compare 强制比对(即使存在主键冲突也继续比对)
--max-size <大小> -1(不限制) 文件大小限制(见通用参数):超限文件仅二进制比对、跳过接口比对,且diffjson 生成报告(标记 sizeExceeded=true,无字段定义/主键信息);diffhtml/diffxlsx 在此场景不生成报告
--ignore-warnings 抑制解析警告输出,退出码不再返回 5、而按比对结果返回 0-4(警告仍记录在报告中)。可容忍轻微警告的自动化场景建议启用
--exp-diff-column <1|2|3> 1 导出列模式:1=仅差异列 2=差异列+忽略列(有差异时) 3=所有列
--exp-diff-line <1|2|3> 1 导出行模式:1=仅差异行 2=差异行+忽略差异行 3=所有行。对 diffhtml 无效(HTML 固定仅导出差异行)

比对输出文件命名规则

未用 -O 指定时:与原文件同目录,<原文件名>.diffresult.json / <原文件名>.diffresult.html / <原文件名>.diffresult.xlsx(均无时间戳)。

-O 指定目录时:json/html 为 <目录>/<原文件名>.diffresult.json/html;xlsx 为 <目录>/<原文件名>.diffresult_<时间戳>.xlsx

比对输出类型差异(单文件比对,OFD/CSV/FIXED/OFD Index 文件)

类型 生成时机
diffxlsx 仅当导出行模式下的结果表非空时生成:默认 --exp-diff-line 1(仅差异行)即接口存在差异行才生成,接口内容一致时不生成;--exp-diff-line 2 在忽略字段存在差异时即使接口内容一致也生成;--exp-diff-line 3 所有行均入报告(含一致行),接口内容一致也生成。二进制一致时无论行模式如何均不生成
diffjson 总是生成 JSON 报告(含摘要信息;二进制一致时仅含 metadata/summary 无数据行;data 行内容同样受 --exp-diff-line 影响——默认模式 1 下接口内容一致时为空数组,模式 3 下含所有行)
diffhtml 生成人类可读的可视化 HTML 报告,单文件差异行上限 5000 行(超出部分不导出;HTML 固定跳过一致行,不受 --exp-diff-line 影响,接口内容一致时输出简化报告)

比对注意事项

  • 比对前提:两个文件必须使用相同的主键定义,否则无法比对。
  • 主键冲突:默认情况下主键冲突会终止比对,使用 --force-compare 可强制继续。
  • 单边字段:默认不比对单边字段,使用 --diff-single-side 可启用。
  • 忽略字段:使用 --ignore-fields 可指定不参与比对的字段。
  • DBF 不支持接口比对:DBF 文件仅做二进制比对,不做接口数据比对(二进制一致退出码 0,不一致退出码 1,与批量"仅二进制不一致"语义一致),stderr 会输出 Note 提示该语义。该场景不生成任何报告文件(diffjson/diffhtml/diffxlsx 均不生成,--stdout 也无 JSON 输出),比对结果仅由退出码与 stderr 提示承载。
  • ZIP 文件:仅二进制比对,不做接口数据比对(二进制一致退出码 0,不一致退出码 1,与批量"仅二进制不一致"语义一致),stderr 同样输出 Note 提示,与 DBF 分支措辞、行为完全一致(同样不生成任何报告文件)。
  • 二进制一致时:无论 --exp-diff-line 如何设置都不导出数据行,仅含 metadata/summary;所有列信息仍在 metadata 中完整导出。

七、批量处理

--batch 启用目录级批量处理,不递归处理子目录(批量导出时检测到子目录会输出警告;批量比对则静默忽略子目录)。单文件模式下传入目录路径而未加 --batch 时,程序会给出友好提示并退出。

批量转换(批量导出)

FFReader -c --batch -f <输入目录> -t <csv|sql|xlsx|json> [可选参数]
参数 说明
-f <目录> 输入目录(必选)
-t <类型> 导出类型:csv / sql / xlsx / json(必选)
-O <目录>/ 输出目录(必须以 / 结尾且已存在)。未指定时在输入目录下自动创建 exportresult_<时间戳> 子目录
--filter <模式> glob 过滤模式(可多次指定),如 --filter "*.txt",支持 *?[abc];优先级高于系统内置排除规则(但不高于 --filter-exclude
--filter-exclude <模式> glob 排除模式(可多次指定),如 --filter-exclude "*.bak";优先级高于 --filter,同时命中时以排除为准
--max-size <大小> 文件大小限制(见通用参数):超过限制的文件跳过不导出
--stdout 仅支持 csv/json/sql(xlsx 不支持);逐文件内容顺序拼接写入 stdout、无文件边界标记(json 为多个 JSON 文档连排,需流式解析;csv 每文件含表头行;sql 语句顺序拼接);进度与摘要走 stderr,不污染数据流
-s / -n / -C / -d / -q / -p 与单文件模式含义相同

输出文件命名:每个文件生成 <文件名>.export.<扩展名>,放在输出目录中。

批量比对

FFReader -c --batch -R <原目录> -N <新目录> -t <diffxlsx|diffjson|diffhtml> [可选参数]
参数 说明
-R <目录> / -N <目录> 原目录和新目录(均必选,两个目录都必须存在)
-t <类型> diffxlsx / diffjson / diffhtml(必选)
-O <路径> 两种形式:以 .json/.html/.xlsx 结尾的文件路径=输出汇总报告(--summary-only 模式下允许,否则必须传目录路径,程序会报错);以 / 结尾的目录路径=输出全部结果到该目录。未指定时在原目录下自动创建 diffresult_<时间戳> 子目录。注意:-O 文件路径只对 diffjson/diffhtml 汇总生效,-t diffxlsx 汇总始终写入 diffresult[_<时间戳>].xlsx,忽略 -O 文件路径
--summary-only 仅导出汇总报告(diffresult.xlsx/json/html),跳过单文件差异报告(*.diffresult.*
--batch-diff-summary-rows <N> 汇总报告中每个文件的最大差异明细行数,取值 10-500,默认 50(仅对批量比对 diffjson/diffhtml 生效;更多明细见单文件报告)
--force-compare 存在主键冲突时仍执行接口比对,主键配置可自定义修改,修改后建议做好本地配置备份
--stdout 仅支持 diffjson。--summary-only 时输出单一汇总 JSON;否则输出逐文件差异 JSON + 汇总 JSON 顺序拼接(多个 JSON 文档连排,需流式解析)
--filter / --filter-exclude / --max-size --filter / --filter-exclude 同批量转换;--max-size 文件大小限制(见通用参数):超限文件仅二进制比对、跳过接口比对,汇总报告(json/xlsx/html 均生成)中标记 sizeExceeded=true,单文件明细报告仅 diffjson 生成(与单文件比对一致,不整体排除)
--ignore-fields / --exp-diff-column / --exp-diff-line / --diff-single-side 同单文件比对模式
-p <配置> 指定解析配置,仅支持单个配置(应用到原、新两文件),不支持单文件比对模式的 | 双配置分隔

批量比对文件匹配规则: 按文件名在两个目录间匹配;仅存在于一方目录的文件标记为单边文件(“Only in original/new directory”),计入结果但不做接口比对。

多配置自动选择(批量比对): 批量比对时若某文件自动匹配到多个解析配置,程序会自动使用第一个匹配的配置继续处理(记录解析警告,不中断批量流程);这与单文件模式不同——单文件比对/导出命中多个配置会报错并列出全部候选配置,需用 -p 指定其一。因此批量比对遇到可疑结果时,建议对该文件单独执行单文件比对并用 -p 锁定配置复核。

批量比对输出:

  • 汇总报告:diffresult.json / diffresult.html(无时间戳);xlsx 为 diffresult_<时间戳>.xlsx(仅自动创建输出目录时含时间戳,指定 -O 目录时为 diffresult.xlsx
  • 单文件差异报告(非 --summary-only 时):json/html 为 <文件名>.diffresult.json/html;xlsx 为 <文件名>.diffresult_<时间戳>.xlsx

八、各文件类型解析说明

OFD 文件(Open Fund Data)

开放式基金交换协议标准格式或其体系内的其他协议,分两种子类型:

OFD Index 文件(索引文件)

  • 文件结构:6 行固定文件头 + 若干索引行(每行一条文件名记录) + OFDCFEND 结束标志
  • 支持导出:csvxlsxjson(JSON 含专用元信息结构,见第十章);SQL 导出未针对其单列结构做适配,不建议使用
  • 支持比对模式(以 filename 为虚拟主键)

OFD Data 文件(数据文件)

  • 文件结构:版本行、文件类型行、字段列表、记录数行,之后为定长数据行
  • 配置文件:config/OFD_<版本>.ini,如 OFD_21.ini
  • 支持全部四种导出格式及比对模式
  • 多配置碰撞时程序会输出所有候选配置供 -p 指定(单文件模式报错;批量比对自动使用第一个匹配配置,见第七章

CSV 文件(固定分隔符文件)

  • 配置文件:config/CSV_*.ini
  • 支持自定义分隔符、首行校验、版本校验、尾部忽略行
  • AUTO 编码使用 LibUcd 自动检测编码(读取文件前 4096 字节);检测结果不在允许列表时回退为 UTF-8,windows-125x / koi8-r 等识别为 GB18030
  • 支持全部四种导出格式及比对模式

FIXED 文件(定长字段文件)

  • 配置文件:config/FIXED_*.ini
  • 支持多种行长度变体(如 NAV 文件)
  • 支持字节定长(fieldlengthtype=0)和字符定长两种模式
  • 增强校验:首行、尾行、版本行、字段数行、字段明细行
  • 支持全部四种导出格式及比对模式

DBF 文件( dBase/FoxPro数据文件)

  • 配置文件:config/DBF_*.ini(提供字段描述翻译,非必须)
  • 自动按文件名通配 + 字段名匹配度(≥30%)选择配置
  • DBF 导出 JSON 时 configSegment 恒为空字符串(DBF 无配置段概念)
  • 支持全部四种导出格式(JSON 导出中所有字段 type 恒为 S、值恒为字符串)
  • 仅支持二进制比对(DBF 文件结构不适用于接口数据比对:二进制一致退出码 0,不一致退出码 1;比对时不生成任何报告文件,见第六章比对输出类型差异)

九、导出格式详解

CSV 导出

  • 引号策略:1=不加引号 2=RFC4180(含分隔符/换行/引号时加引号,默认) 3=全部加引号
  • 输出文件含标题行(字段描述 + 字段名,如 基金代码(FundCode)
  • 0 行文件仍创建只含标题行的空 CSV

Excel 导出(xlsx)

  • 最大行数限制:100 万行(超出报错退出,建议改用 CSV 或 SQL)
  • 标题行:绿色背景、居中、加粗
  • 数值型字段(N 类型)自动应用千分位格式
  • 字段宽度自适应内容长度

JSON 导出

JSON 导出专为 AI 分析和程序解析设计,包含完整的元信息和数据结构,流式生成(超大文件不受内存限制),文件输出与 --stdout 输出内容一致。详细 Schema 见第十章

SQL 导出

  • 必须搭配 -s 参数提供 SQL 模板
  • 模板中用 %N(N 从 1 起)引用字段,如 %1 = 第 1 字段
  • '%N' 模式(单引号包围):程序自动处理引号,空值 + -n 时输出裸 NULL 而非 ''
  • %N 模式(无引号):值直接替换,适用于数值字段
  • 字段值中的单引号自动转义为 ''(ANSI SQL 标准)
  • 模板中不允许出现 %0,字段编号超出实际字段数时报错

SQL 模板示例:

-- 字符串字段加引号,数值字段不加引号
INSERT INTO fund_nav VALUES('%1','%2',%3,%4,'%5');

-- 所有字段均为字符串
INSERT INTO t (code,name,amt) VALUES('%1','%2','%3');

-- 搭配 -n 参数处理可空字段(空值自动输出 NULL)
INSERT INTO t VALUES('%1','%2','%3');
-- 不加 -n:INSERT INTO t VALUES('A001','','')
-- 加 -n:INSERT INTO t VALUES('A001',NULL,NULL)

COMMIT 控制:

# 每 1000 行插入一条 COMMIT(-C 取值 1-100000)
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t sql -s "INSERT INTO t VALUES('%1');" -C 1000

十、JSON 结构说明

程序共有三类 JSON 输出,schema 各不相同:

JSON 类型 产生方式
数据导出 JSON -t json(单文件 / --batch 批量 / --stdout
单文件比对 JSON -t diffjson(含批量比对生成的 *.diffresult.json 单文件报告)
批量比对汇总 JSON --batch -t diffjsondiffresult.json--stdout

数据导出 JSON Schema(-t json)

顶层结构(键按出现顺序):

{
  "metadata": {
    "ai_parse_hint": "...",
    "fileType": "OFD",
    "configFile": "OFD_21.ini",
    "configSegment": "[04_001_FUND]",
    "description": "开放式基金-交易类确认",
    "fields": [
      {"name": "AppSheetSerialNo", "describe": "申请单编号/申请编号", "type": "S"},
      {"name": "LargeRedemptionFlag", "describe": "巨额赎回处理标志", "type": "S", "dict": {"0": "取消", "1": "顺延"}},
      {"name": "ConfirmedVol", "describe": "确认份额", "type": "N"}
    ],
    "primaryKey": ["TASerialNO"]
  },
  "data": [
    {"rowNum": 1, "lineNum": 133, "fields": {"AppSheetSerialNo": "20181015002403", "LargeRedemptionFlag": "0", "ConfirmedVol": 90000000.0}}
  ],
  "parseWarnings": ["Missing end marker: OFDCFEND not found"],
  "primaryKeyConflict": { "hasConflict": true, "conflictKeys": [{"key": "20181015002403", "count": 2}], "totalConflictKeys": 1, "totalRows": 1066, "uniqueRows": 1065 }
}

metadata 对象字段:

字段 类型 说明
ai_parse_hint string AI 解读指引全文,内嵌完整的结构说明与解读要求
fileType string 文件类型标识:OFD / CSV / FIXED / DBF / OFDIndex
header object 仅 OFD Index 文件存在,6 行文件头的解析结果
totalFiles number 仅 OFD Index 文件存在,实际索引记录数
configFile string 解析使用的配置文件名(DBF 未匹配到配置时为 DBF_AUTO
configSegment string 配置段名;DBF 文件恒为空字符串
description string 接口文件描述(如"开放式基金-交易类确认")
fields array 字段定义数组
primaryKey array<string> 可选键,OFD/CSV/FIXED 数据文件且配置定义了主键时输出;DBF 文件不输出此键

metadata.fields[] 元素:

字段 类型 说明
name string 字段名,即 data[].fields 的键名;配置中字段名为空时回退使用中文描述
describe string 字段中文描述,非空时输出
type string N=数值,S=非数值(含字符串、字符、日期时间等)。DBF 文件所有字段恒为 S
dict object 可选,枚举值→含义映射,按键升序排列

primaryKeyConflict 对象(可选): 仅当使用 --check-primary-key 且检测到主键冲突时输出;位于 dataparseWarnings 之后(主键冲突需在全部数据行写入完成后统计)。仅对配置了主键(fieldprimarylist字段索引从 0 开始,格式见第十一章配置系统与 -p 参数)的 OFD/CSV/FIXED 数据文件生效,DBF/OFD Index 文件无主键配置,永不输出该段:

字段 说明
hasConflict 是否存在主键冲突
conflictKeys 每个元素为 {"key": "主键值", "count": 出现次数}
totalConflictKeys 冲突主键总数
totalRows 总数据行数
uniqueRows 唯一主键数

data[] 元素(数据文件):

字段 说明
rowNum 数据行号,从 1 开始
lineNum 原始文件物理行号(含文件头),从 1 开始;如某交易类确认文件头 132 行时首条数据 lineNum=133
fields 全部字段的键值对

data 取值规则:

  • type: "N" 且值可转换为数值时输出 JSON 数字,否则(含空值、转换失败)输出字符串
  • DBF 文件所有字段值均为字符串(type 恒为 S);DBF 的 rowNumlineNum 相同(无文件头)
  • parseWarnings 数组始终输出,位于 JSON 尾部;无警告时为空数组 []

字段键名规则(重要):

data[].fields 的键名严格等于 metadata.fields[].name,而 name 的内容由所用配置文件决定,因此不同文件类型/配置的键名风格不同,不能假设统一为英文:

  • 解析 data不要硬编码字段名,应先读 metadata.fields[].name 再按名取值
  • 同一个 name 可能重复出现语义相同但风格不同的写法,交叉核对请以 metadata.fields 为准
  • metadata.fields[].describe 为字段中文释义,可用于向用户展示可读名称

OFD Index 文件 JSON 专有结构

{
  "metadata": {
    "ai_parse_hint": "...",
    "fileType": "OFDIndex",
    "header": {
      "identifier": "OFDCFIDX",
      "version": "22",
      "creator": "918A",
      "receiver": "YZX",
      "date": "20210318",
      "fileCount": "5",
      "actualFileCount": 5
    },
    "totalFiles": 5,
    "configFile": "OFD_IndexFile.ini",
    "configSegment": "[OFDINDEXFILE]",
    "description": "OFD Index File",
    "fields": [{"name": "filename", "describe": "文件名", "type": "S"}]
  },
  "data": [
    {"rowNum": 1, "lineNum": 7, "fileName": "OFD_918A_YZX_20210318_01.TXT"}
  ],
  "parseWarnings": ["File count mismatch: declared 4, actual 5"]
}

header 对象字段:

字段 说明
identifier 文件标识,规范固定值 OFDCFIDX
version 版本号(如 22 表示 2.2 版本)
creator 文件创建人代码
receiver 文件接收人代码
date 日期,YYYYMMDD(与文件名中日期一致,非机器时间)
fileCount 声明的数据文件个数
actualFileCount 实际解析的索引记录数

data[] 元素(OFD Index):

字段 说明
rowNum 数据行号,从 1 开始
lineNum 原始文件行号,从 7 开始(前 6 行为文件头)
fileName 数据文件名(注意:无 fields 对象,键名为 fileName

校验提示:header.fileCountheader.actualFileCount 不一致表示声明与实际不符;重复文件名、缺少 OFDCFEND 结束标志等会记入 parseWarnings

单文件比对 JSON(diffjson)Schema

顶层为 metadata / summary / data 三个键(批量比对生成的 *.diffresult.json 单文件报告同此结构):

{
  "metadata": {
    "ai_parse_hint": "...",
    "fileType": "FIXED",
    "oriFilePath": "/data/oldpath/C103100259-Z700110227-001-20230725-01.txt",
    "oriConfigFile": "FIXED_WDEP_理财产品中央数据交换协议_V1.0.ini",
    "oriConfigSegment": "[??????????-??????????-001-20??????-*.txt*|1.0]",
    "oriDescription": "001-01-账户申请",
    "newFilePath": "/data/newpath/C103100259-Z700110227-001-20230725-01.txt",
    "newConfigFile": "FIXED_WDEP_理财产品中央数据交换协议_V1.0.ini",
    "newConfigSegment": "[??????????-??????????-001-20??????-*.txt*|1.0]",
    "newDescription": "001-01-账户申请",
    "fields": [{"name": "AppSheetSerialNo", "describe": "申请单编号", "type": "S"}, {"name": "IndividualOrInstitution", "describe": "个人/机构标志", "type": "S", "dict": {"0": "个人", "1": "机构", "2": "产品", "3": "私募产品", "9": "全国"}}],
    "primaryKey": ["AppSheetSerialNo"],
    "ignoredFields": ["Address"]
  },
  "summary": {
    "success": true,
    "binaryEqual": false,
    "sizeExceeded": false,
    "sizeExceedDetail": "",
    "errorMessage": "",
    "versionEqual": true,
    "contentEqual": false,
    "oriRows": 4,
    "newRows": 4,
    "oriPrimaryConflict": false,
    "oriPrimaryConflictKeys": [],
    "newPrimaryConflict": false,
    "newPrimaryConflictKeys": [],
    "forceCompare": false,
    "totalDiffCount": 1,
    "warnMessage": ""
  },
  "data": [
    {
      "primaryFields": {"AppSheetSerialNo": "998320230725000000984919"},
      "diffFields": {"IndividualOrInstitution": {"oldValue": "1", "newValue": "0"}},
      "result": "比对不一致"
    }
  ]
}

summary 对象字段(全部键始终输出):

字段 说明
success 比对流程是否成功执行
binaryEqual 二进制是否一致
sizeExceeded 是否因超过大小限制跳过接口比对
sizeExceedDetail 超限详情,无超限时为空字符串
errorMessage 错误信息,无错误时为空字符串
versionEqual 接口版本是否一致;null=未进行接口解析(超限或解析失败)
contentEqual 接口数据内容是否一致
oriRows / newRows 原/新文件数据行数
oriPrimaryConflict / newPrimaryConflict 原/新文件是否存在主键冲突
oriPrimaryConflictKeys / newPrimaryConflictKeys 冲突主键详情,元素为 {"key": "主键值", "count": 出现行数};联合主键各字段值以 - 连接
forceCompare 是否强制比对
totalDiffCount 总差异行数(不一致+新增+删除);-1 表示未比对/解析失败/无主键
warnMessage 警告信息;存在主键冲突时输出"仅首条重复主键记录参与比对"提示

data[] 元素(每行一条差异记录):

字段 说明
primaryFields 主键字段名->字段值(有主键配置时才存在该键)
diffFields 差异字段:双边差异为 {"oldValue": "原值", "newValue": "新值"} 对象;单边记录(新增/删除)直接为值字符串。模式 1/2 下单边记录此对象为空
ignoredDiffFields 被忽略字段的差异(仅模式 2/3 输出)
sameFields 一致字段及其值(仅模式 3 输出)
result 行结果:比对一致 / 忽略指定列后一致 / 比对不一致 / 原文件中无此记录(新增) / 新文件中无此记录(删除)

行结构随 --exp-diff-column 模式变化:模式 1=primaryFields+diffFields+result;模式 2=模式 1+ignoredDiffFields;模式 3=模式 2+sameFields

行数由 --exp-diff-line 控制(1 仅差异行、2 差异+忽略差异行、3 所有行);二进制一致时 data 恒为空数组

注:data 记录中不含 rowNum/lineNum 行号,记录定位以 primaryFields 为准。

批量比对汇总 JSON Schema(–batch -t diffjson)

顶层为 metadata / summary / files 三个键:

{
  "metadata": {
    "ai_parse_hint": "...",
    "batchMode": true,
    "oriDirectory": "/data/oldpath/",
    "newDirectory": "/data/newpath/",
    "exportType": "diffjson"
  },
  "summary": {
    "totalFiles": 8,
    "binaryMatchCount": 5,
    "contentMatchCount": 0,
    "contentMismatchCount": 2,
    "singleSideCount": 0,
    "binaryMatchSkippedCount": 0,
    "binaryMismatchSkippedCount": 1,
    "unknownCount": 0,
    "summaryOnly": true
  },
  "files": [ {"fileName": "C103100259-Z700110227-001-20230725-01.txt", "...": "..."} ]
}

summary 对象字段:

字段 说明
totalFiles 参与比对的总文件数
binaryMatchCount 二进制完全一致的文件数
contentMatchCount 接口数据内容一致的文件数(不含二进制一致的)
contentMismatchCount 接口数据不一致的文件数
singleSideCount 单边文件数(仅一方目录存在)
binaryMatchSkippedCount 无法接口比对(超限/无主键/主键冲突等)且二进制一致的文件数
binaryMismatchSkippedCount 无法接口比对且二进制不一致的文件数
unknownCount 未知状态的文件数(兜底归类)
summaryOnly 是否仅导出汇总

files[] 元素(每个文件一条记录):

字段 说明
fileName 文件名(两目录间按文件名匹配)
hasOriFile / hasNewFile 原/新目录是否存在该文件
oriFilePath / newFilePath 原/新文件完整路径
binaryEqual 二进制是否一致
contentEqual 内容是否一致
versionEqual 接口版本是否一致;null=未进行接口解析
compareResult 标准化结果:Binary identical / Content identical / Content mismatch / Single-side file / Binary identical (binary-only comparison) / Binary mismatch (binary-only comparison) / Unknown
oriRows / newRows 原/新文件行数;null=未解析
oriPrimaryConflict / newPrimaryConflict 是否存在主键冲突
oriPrimaryConflictCount / newPrimaryConflictCount 冲突主键数;null=未检查
resultFilePath 单文件差异报告路径(生成了单文件报告时非空:含二进制一致、内容一致、内容不一致及超限 diffjson 报告;未生成报告时为空:DBF/ZIP 二进制兜底、单边文件、空文件、解析失败、diffxlsx 内容一致、--summary-only、stdout 模式)
interfaceCompareResult 接口比对结果描述(与 compareResult 的标准化英文描述一致)
errorMessage 错误信息(仅失败时有值)
beginTime / endTime 开始/结束比对时间
sizeExceeded 是否超限跳过接口比对
sizeExceedDetail 超限详情(无超限时为空字符串)
fields 字段定义(仅不一致且有已解析差异时非空,按 --exp-diff-column 模式筛选,主键列始终包含)
primaryKey 主键列表(无差异数据时为 []
hasParsedDiffData 是否有已解析的差异明细
totalDiffCount 差异总行数
topDiffRecords 前 N 条差异摘要(N 由 --batch-diff-summary-rows 控制,默认 50,取值 10-500)

topDiffRecords[] 元素:

字段 说明
primaryFields 主键字段名->字段值
diffFields 差异字段(格式同单文件 diffjson 的 diffFields)
result 比对不一致 / 原文件中无此记录(新增) / 新文件中无此记录(删除)

十一、配置系统与 -p 参数

配置文件位于程序目录下的 config/ 子目录:

文件模式 用途
OFD_<版本>.ini OFD 数据文件解析规则(如 OFD_21.ini
CSV_*.ini CSV 文件解析规则
FIXED_*.ini 定长字段文件解析规则
DBF_*.ini DBF 字段名翻译
OFD_IndexFile.ini OFD 索引文件定义
OFD_CodeInfo.ini 发送方/接收方机构代码映射
OFD_Dictionary.ini OFD 字段枚举值翻译

配置文件均为 UTF-8 编码的 INI 格式,修改后无需重新编译,重启程序即生效。

接口段内的主键配置(fieldprimarylist)

OFD/CSV/FIXED 配置文件的每个接口段(如 [01_001_FUND])内,在字段定义之后可配置主键:

fieldprimarylist="8"          # 单字段主键
fieldprimarylist="0,4,8"      # 联合主键(多个索引,逗号分隔)

解读规则:

  • 字段索引从 0 开始0 = 段内第 1 个字段,4 = 第 5 个字段),与字段定义行 1=...2=... 的行号差 1,配置时务必注意
  • 多个索引构成联合主键,程序加载时自动去重并按升序排列
  • 索引超出字段总数(COUNT)时该索引被忽略(不参与主键功能,不报错)
  • 该配置仅对 OFD/CSV/FIXED 数据文件生效;DBF、OFD Index 文件无主键配置

示例(OFD_22.ini[02_001_FUND] 段,共 27 个字段):

fieldprimarylist="8"

含义:主键为 0 基索引 8,即第 9 个字段 TASerialNO(TA确认交易流水号)。同文件 [01_001_FUND] 段的 fieldprimarylist="4" 即第 5 个字段 AppSheetSerialNo(申请单编号)。

主键配置是以下功能的前提:

  • 单文件/批量比对的接口比对(无主键配置时比对退出码 2
  • JSON 导出的 metadata.primaryKey 字段
  • --check-primary-key 主键冲突检测(冲突时退出码 5,明细见 primaryKeyConflict 节点)
  • 不同公司对主键的认定可能不同,可直接编辑配置段调整主键定义,修改后建议做好本地配置备份

接口段内的必填规则配置(fieldcheck_XXXX)

接口段内还支持以 fieldcheck_ 为前缀的必填规则,可配置多条(fieldcheck_0001fieldcheck_0002…),格式为 "条件|必填字段列表"

fieldcheck_0001="11=1&18=001|5,6,7,8,9,10,11,17,18,32"
                 └── 条件部分 ──┘└──────── 必填字段列表 ────────┘
部分 语法 说明
条件 序号=值 序号从 1 开始(与 fieldprimarylist 的 0 基索引不同);多个条件用 & 连接(且关系);多组条件用 ; 连接(或关系);条件部分写 ALL 表示对所有行无条件生效
必填字段列表 序号1,序号2,... 序号从 1 开始;命中条件的行中这些字段不能为空

解读规则:

  • 条件值与解析后的字段原始值做精确相等比较(不做字典翻译)
  • 必填序号超出字段总数(COUNT)时该序号被忽略;序号非法则整条规则不加载
  • 该规则仅 GUI 的必填校验功能使用,CLI 导出/比对不执行必填校验

示例(OFD_22.ini[01_001_FUND] 段):

fieldcheck_0001="11=1&18=001|5,6,7,8,9,10,11,17,18,32"

含义:当第 11 个字段(个人/机构标志 IndividualOrInstitution)为 1 且第 18 个字段(业务代码 BusinessCode)为 001 时,第 5、6、7、8、9、10、11、17、18、32 个字段必填。

易混淆点fieldprimarylist 的索引从 0 开始,fieldcheck_ 的序号从 1 开始,两套编号体系不一致,编写配置时需分别对待。

-p 参数格式

# OFD / CSV / FIXED 文件:需指定配置文件名 + 配置段(双括号格式)
-p "[OFD_21.ini][04_001_FUND]"

# DBF 文件:只需指定配置文件名(单括号格式)
-p "[DBF_上海证券登记结算数据接口.ini]"

# 单文件比对模式:两个文件可用不同配置,用 | 分隔
-p "[OFD_21.ini][04_001_FUND]|[OFD_21.ini][04_001_FUND]"
# 或两个文件用相同配置时只需指定一个
-p "[OFD_21.ini][04_001_FUND]"

# FIXED 配置段可能含通配符(按配置文件中实际段名书写)
-p "[FIXED_WDEP_理财产品中央数据交换协议_V1.0.ini][??????????-??????????-001-20??????-*.txt*|1.0]"

注意:| 双配置分隔仅单文件比对模式支持;批量比对 -p 只接受单个配置,应用到原、新两文件。

校验规则:

  • 第一个括号内容必须以 OFD_CSV_FIXED_DBF_ 开头
  • OFD/CSV/FIXED 必须提供双括号(文件名+配置段),DBF 仅需单括号
  • 比对模式 -p| 分隔时必须是 1 个或 2 个配置,多于 2 个报错
  • 指定的配置文件和配置段必须实际存在,否则报错

十二、退出码速查表

转换模式(单文件导出)

退出码 含义
0 导出成功,无解析警告
5 导出成功,但存在解析警告(如缺少文件结束标志、尾部内容不匹配),或 --check-primary-key 检测到主键冲突
-1 导出失败

比对模式(单文件 diff)

退出码 含义
0 比对一致:文件内容相同,无警告,无主键冲突
1 比对不一致:文件内容不同,无警告,无主键冲突(含 ZIP/DBF 仅二进制不一致,与批量比对该场景的退出码语义一致)
2 无主键配置:原文件或新文件(或两者)未配置主键,无法进行接口比对
3 内容一致但存在主键冲突(–force-compare 强制比对完成,或二进制一致但检测到主键冲突)
4 强制比对完成,内容不一致且有主键冲突
5 警告:比对完成但存在解析警告(如缺少结束标志)或配置类警告(如二进制一致但配置未定义主键)
-1 比对失败:解析错误、配置错误、主键冲突未强制比对等

注:退出码 0-4 表示无警告;只要存在警告(解析警告或配置类警告,如"Config has no primary key defined"),无论比对结果如何退出码均为 5(警告状态优先于比对结果)。无主键配置的退出码与二进制一致性有关:二进制不一致时无主键返回 2(无法接口比对),二进制一致时无主键降级为警告返回 5。若可容忍轻微警告,可加 --ignore-warnings:退出码将直接反映比对结果本身(0-4)。需注意:解析警告与配置类警告不写入比对 JSON(diffjson),--ignore-warnings 后也不会输出到 stderr;比对 JSON 中唯一保留的警告是主键冲突(经 summary.warnMessage 字段记录)。

批量模式(批量导出和diff)

退出码 含义
0 全部文件处理成功(批量比对:全部一致)
1 仅批量比对:存在差异(数据不一致/单边文件/仅二进制不一致),比对正常完成,非执行错误(与单文件比对退出码 1 语义一致)
-1 参数错误或无效参数
6 批量导出:部分文件导出失败;批量比对:部分文件比对结果无法归类(执行异常)

注:批量比对退出码不受解析警告影响(批量模式内部等效忽略警告,警告记录在 JSON 报告中),故批量比对无退出码 5。

退出码读取注意

注意:比对模式(单文件/批量)的退出码 1 表示"存在差异",属比对正常完成,不是失败

注意:因使用环境的环境不同,可能会出现错误码被转义的情况,编写脚本前建议做好验证

程序实际返回的失败退出码为 -1,不同 shell 读取到的值不同(判断请按"非 0 即失败",不要依赖具体数值):

执行环境 -1 的实际表现
PowerShell($LASTEXITCODE -1
cmd(%ERRORLEVEL% -1
macOS / Linux shell(zsh / bash,echo $? 255(-1 的 8 位无符号表示)
Git Bash / MSYS(echo $? 127(MSYS 层转换所致,非程序真实返回值)

十三、错误信息与排查

错误信息 含义 处理建议
File not recognized. Supported formats: OFD, CSV, FIXED, DBF. Please provide a parse config (add to config/ directory or specify with -p) and try again 文件类型无法识别(非文本/二进制文件、文本未被任何配置命中且自动引擎无法归类(无规整分隔符结构)、单行数据过长等场景均统一输出本条) 补全解析配置(config/ 目录)或用 -p 指定已有配置后重试;若文件本身为二进制/损坏文件则无法解析
Unsupported file format: ... 文件后缀属于不支持的类型(压缩包/音视频/图像/Office 等,CLI 中压缩文件统一提示先解压) 压缩文件先解压再解析;其余类型不支持解析
This is an OK file of an OFD data file OFD 数据文件的 OK 回执文件 请解析对应的原始数据文件
This is a sqlldr bad file sqlldr 导入生成的 bad 文件 请解析对应的原始数据文件
This is a sqlldr control file sqlldr 导入使用的控制文件 请解析对应的原始数据文件
This is a file shortcut 文件快捷方式 请解析快捷方式指向的原始文件
No CSV config matches this file 所有 CSV 配置均未命中该文件 CLI 暂不支持无配置的自动解析 CSV 文件(该能力仅 GUI 提供),建议在 config/ 下补全对应解析配置后重试,或用 -p 指定已有配置
Auto-detected CSV does not support interface comparison 比对模式下自动识别的 CSV(疑似固定分隔符文本文件,无配置解析)无字段定义与主键,无法接口比对(退出码 -1) 在 config/ 下补全含字段定义与主键的解析配置后重试,或用 -p 指定已有配置
File matches both CSV and fixed-length configs CSV 和 FIXED 配置同时命中 -p 指定正确配置
File matches multiple configs 多个同类型配置均匹配 从输出的候选列表中选择 -p 参数
Field count mismatch 配置字段数与文件不符 检查文件版本,更换对应配置
Row length mismatch 行长度与配置不符 文件可能不是本配置对应的版本
Config [xxx] not found -p 指定的配置不存在 检查配置文件名和配置段名称拼写
Quote strategy (-q) is required for CSV export 单文件 CSV 导出未传 -q 补充 -q 1/2/3(推荐 -q 2
SQL template contains no field placeholders SQL 模板无 %N 占位符 在模板中加入 %1%2 等占位符
SQL template contains %0 which is invalid 占位符序号为 %0 或更小(字段编号必须 ≥ 1) 占位符从 %1 开始,勿使用 %0
SQL template references field %N but file only has M 占位符序号超出字段数 检查字段数量,占位符从 %1 开始
File already exists 目标文件已存在 -o 参数覆盖,或指定不同的 -O 路径
File exceeds Excel export limit 超过 100 万行限制 改用 CSV 或 SQL 导出
DBF file does not support interface comparison DBF 文件比对提示(.dbf 后缀预检查或 -p 指定 DBF 配置路径;stderr 同时输出 Note:DBF 仅支持二进制比对,不支持接口数据比对) 属正常提示非报错:二进制一致退出码 0,不一致退出码 1(正常完成态,非执行错误)
ZIP file does not support interface comparison ZIP 文件比对预检查提示(stderr 同时输出 Note:ZIP 仅支持二进制比对,不支持接口数据比对) 属正常提示非报错:二进制一致退出码 0,不一致退出码 1(正常完成态,非执行错误)
No common primary key, cannot diff 两文件主键定义不匹配 确保两文件使用相同的主键配置
Primary key conflict in original/new file 文件存在主键冲突 使用 --force-compare 强制比对
Directory path detected but --batch parameter not specified 传入了目录但未加 --batch --batch,或改为具体文件路径
Directory path must end with / 批量模式 -O 目录路径未以 / 结尾 改为 -O /path/to/dir/ 形式
Invalid config format -p 格式错误 使用 [OFD_21.ini][04_001_FUND][DBF_上海证券登记结算数据接口.ini] 格式
First bracket must start with DBF_, OFD_, CSV_, or FIXED_ 配置文件名前缀不合法 检查配置文件名前缀
Commit value must be an integer between 1 and 100000 -C 超出取值范围 使用 1-100000 之间的整数
Delimiter must be between 1 and 10 characters 分隔符长度不合法 使用 1-10 个字符,且不含换行/引号/反斜杠
Invalid --batch-diff-summary-rows parameter 该参数超出范围 使用 10-500 之间的整数
Invalid --max-size parameter 大小参数格式错误 使用如 100MB1GB500KB 或纯字节数
Failed to commit temp file: ... 临时文件落地为目标文件失败(rename 与 copy 兜底重试均失败,多因目标文件被占用、目录权限不足或磁盘空间不足) 检查输出目录权限与磁盘空间,关闭占用目标文件的程序(杀毒/索引/编辑器等)后重试
... failed to remove temp file ... 临时文件清理失败(残留的 .ffreader_*.tmp 临时文件被占用无法删除) 属非致命告警,不影响导出/比对结果,可手动删除残留的临时文件

排查通用建议:

  1. 优先让用户不带 -p 运行,查看自动匹配结果和失败原因
  2. 若输出 Matched configs 列表,让用户从中选择 -p 参数
  3. 若输出 Match failure reasons,逐条分析原因(字段数、行长、版本等)

运行时临时文件提示: 导出与比对写文件时采用「临时文件 → 原子落地」保护机制,临时文件命名为 <目标文件名>.ffreader_<时间戳>_<进程PID>.tmp.ffreader 前缀标识本程序临时文件,避免与用户文件混淆)。若某次运行异常中断(如进程崩溃)残留了临时文件,下一次导出/比对开始前会自动清理,此时 stderr 输出 Cleaned up N stale temp file(s) in <目录>(仅在有残留时输出,属正常提示、非报错,不影响退出码)。


十四、常用示例汇总

文件转换示例

# 1. 自动识别 OFD 文件,导出 CSV(单文件 CSV 导出必须带 -q)
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t csv -q 2

# 2. 导出 Excel,覆盖已有文件,指定路径
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t xlsx -o -O output.xlsx

# 3. 指定配置解析(当自动匹配到多个配置时使用)--如果你的文件匹配到了多套配置,你可以选择删除不需要的配置,避免需要指定配置
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t csv -q 2 -p "[OFD_21.ini][04_001_FUND]"

# 4. DBF 文件导出 JSON(自动按文件名+字段名匹配翻译配置)
FFReader -c -f TZXX.DBF -t json -O output.json

# 5. OFD 文件导出 JSON 并检查主键冲突
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t json --check-primary-key -O output.json

# 6. SQL 导出,空字段输出 NULL,每 500 行 COMMIT
FFReader -c -f NAVREST20181012 -t sql \
  -s "INSERT INTO fund_nav(code,date,nav) VALUES('%1','%2',%3);" \
  -n -C 500

# 7. 使用管道分隔符导出 CSV(不加引号)
FFReader -c -f A054_XXX_20220429_007_1.txt -t csv -d "|" -q 1

# 8. JSON 导出忽略警告输出
FFReader -c -f OFD_XXX_XX_20111123_03.TXT -t json --ignore-warnings -O output.json

# 9. 转换结果直接输出到 stdout(不生成文件,适合管道给其他工具/AI)
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t json --stdout
FFReader -c -f OFD_XXX_XXX_20181016_04.TXT -t csv -q 2 --stdout

文件比对示例

# 1. 比对两个定长格式文件,输出差异 Excel
FFReader -c -t diffxlsx -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt

# 2. 比对并输出 JSON 格式差异报告
FFReader -c -t diffjson -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt

# 3. 比对并输出 HTML 可视化差异报告
FFReader -c -t diffhtml -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt

# 4. 指定配置进行比对(FIXED 配置段含通配符时按实际段名书写)
FFReader -c -t diffjson -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt -p "[FIXED_WDEP_理财产品中央数据交换协议_V1.0.ini][??????????-??????????-001-20??????-*.txt*|1.0]"

# 5. 比对时忽略某些字段,导出所有行
FFReader -c -t diffjson -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt \
  --ignore-fields "Address,RegionCode" --exp-diff-line 3

# 6. 强制比对(存在主键冲突时继续)
FFReader -c -t diffxlsx -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt --force-compare

# 7. 比对单边字段,导出差异列+忽略列
FFReader -c -t diffxlsx -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt \
  --diff-single-side --exp-diff-column 2

# 8. 指定输出路径并覆盖
FFReader -c -t diffxlsx -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt -O result.xlsx -o

# 9. 差异 JSON 直接输出到 stdout
FFReader -c -t diffjson -R /data/oldpath/C103100259-Z700110227-001-20230725-01.txt -N /data/newpath/C103100259-Z700110227-001-20230725-01.txt --stdout

注:比对示例中 /data/oldpath//data/newpath/ 为目录占位符,请替换为实际的原/新文件路径。

批量转换示例

# 1. 目录下全部文件导出 JSON(输出到 exportresult_<时间戳> 目录)
FFReader -c --batch -f /data/datafile/ -t json

# 2. 仅处理 *.txt 文件,排除备份文件
FFReader -c --batch -f /data/datafile/ -t csv -q 2 --filter "*.txt" --filter-exclude "*.bak"

# 3. 指定输出目录(必须以 / 结尾且已存在)并限制文件大小
FFReader -c --batch -f /data/datafile/ -t xlsx --max-size 100MB -O /data/datafile/export/

# 4. 批量 SQL 导出(模板参数同单文件模式)
FFReader -c --batch -f /data/datafile/ -t sql -s "INSERT INTO t VALUES('%1','%2');" -n -C 1000

批量比对示例

# 1. 两个目录批量比对,输出 JSON 汇总+单文件报告(/data/oldpath/ 与 /data/newpath/ 为目录占位符)
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson

# 2. 仅过滤 C103 开头的文本文件比对
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffxlsx --filter "C103*.txt"

# 3. 仅输出汇总报告(跳过单文件差异报告)
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson --summary-only

# 4. 汇总报告输出到指定文件
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson --summary-only -O ./result.json

# 5. 汇总报告中每文件差异明细扩展到 200 行
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffhtml --batch-diff-summary-rows 200

# 6. 超大文件仅二进制比对(跳过接口比对)
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson --max-size 1GB

# 7. 主键冲突时仍强制接口比对
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson --force-compare

# 8. JSON 输出到 stdout(逐文件差异 JSON + 汇总 JSON 顺序拼接,多个 JSON 文档连排)
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson --stdout

# 9. 强制比对(存在主键冲突时继续)&& 仅仅输出差异摘要报告 && 忽略指定字段 && 限制数据接口比对大小 --这是一个生产验证过的方案,比如开放式基金文件比对仅仅生成摘要供AI分析,且大于1GB的文件仅仅进行二进制比较,防止内存占用超过预期
FFReader -c --batch -R /data/oldpath/ -N /data/newpath/ -t diffjson --force-compare --batch-diff-summary-rows 200 --max-size 1GB --summary-only -O ./result.json

十五、注意事项

  • Windows 路径中若含空格,务必用引号包裹:-f "D:\my data\OFD_XXX_XXX_20181016_04.TXT"
  • Windows 下请使用独立的 FFReaderCli 程序执行命令行操作:原生控制台程序,数据走 stdout、状态信息走 stderr,管道与重定向直接可用;GUI 程序(FFReader-*.exe)传入 -c 等命令行参数时仅弹窗提示改用 FFReaderCli
  • SQL 模板中的分号(;)是 SQL 语句结束符,需保留在模板末尾
  • -n(null-empty)仅影响 SQL 导出,CSV/JSON/Excel 导出中空字段始终输出空字符串
  • 单文件 CSV 导出必须显式提供 -q(引号策略);批量导出中 -q 可省略(默认 RFC4180)
  • 批量模式不递归处理子目录;批量模式 -O 目录路径必须以 / 结尾且目录已存在
  • OFD Index 文件支持 JSON 导出(专用元信息结构)与比对模式(虚拟主键 filename);SQL 导出未针对其单列结构适配,不建议使用
  • DBF 文件仅支持二进制比对(二进制一致退出码 0,不一致退出码 1,与批量"仅二进制不一致"语义一致),不支持接口数据比对(行为与 ZIP 一致)
  • DBF 文件 JSON 导出的 configSegment 恒为空字符串,且所有字段 type 恒为 S(值均为字符串)
  • DBF 文件 JSON 导出的 rowNumlineNum 值相同(无文件头)
  • 输出文件编码统一为 UTF-8(含 BOM 头取决于平台),建议用支持 UTF-8 的工具打开
  • 比对模式要求两文件主键定义一致,否则无法比对
  • --stdout-o/-O 互斥(启用 stdout 时输出路径参数被忽略)
  • zip 或其他格式的压缩文件,需先使用外部工具解压缩后再进行解析和比对
  • Excel 导出有 100 万行限制,超大文件请用 CSV 或 SQL;比对模式的 xlsx 差异报告同样受此限制,HTML 差异报告单文件上限 5000 差异行
  • SQL 大批量导入时推荐 -C 1000(每千行 COMMIT 一次),避免事务过大
  • 流式写出机制确保内存占用恒定,即使文件有数百万行也能正常处理(csv/json/sql 导出)
  • xlsx 导出(数据全量载入内存)与比对模式(新旧文件均载入内存)不受流式机制保护,大文件场景可用 --max-size 限制文件大小以控制内存占用:批量导出超限文件跳过不导出;批量比对超限文件仅二进制比对(跳过接口比对),汇总报告标记 sizeExceeded=true,单文件明细报告仅 diffjson 生成

十六、在 AI 工具中使用(Skill 安装)

FFReader 随包提供一个技能文件 SKILL.md(位于程序包根目录)。将该文件连同可执行程序放入 AI 工具的技能目录后,即可在 Claude CodeWorkBuddy 等 AI 编程工具中以自然语言直接调用 FFReader,完成文件转换、批量处理与文件比对(diff),无需手动记忆命令行参数。

需要复制的文件

文件 说明
SKILL.md 技能说明文件(程序包根目录),AI 据此理解如何调用 FFReader
可执行程序 按平台选择,见 二、运行环境与可执行程序
config/ 配置目录 仅 Windows 需与可执行程序同级;Linux 首次运行自动解压到 ~/.ffreader/config/,macOS 集成在 .app

推荐目录结构

技能运行时按「技能目录 → 用户指定目录 → 环境变量配置路径」的顺序查找可执行程序。最简单可靠的做法,是把可执行程序(以及 Windows 下的 config/)与 SKILL.md 放在同一技能目录下:

<技能根目录>/ffreader/
├── SKILL.md                  # 技能说明文件
├── FFReaderCli-x64.exe       # 可执行程序(此处以 Windows 为例)
└── config/                   # Windows 必需;Linux / macOS 可省略

Claude Code

技能目录(二选一):

作用域 路径 说明
用户级(推荐) ~/.claude/skills/ffreader/ 全局生效,所有项目可用
项目级 <项目根目录>/.claude/skills/ffreader/ 仅当前项目可用

安装步骤(以 macOS / Linux 用户级为例):

mkdir -p ~/.claude/skills/ffreader
cp SKILL.md ~/.claude/skills/ffreader/
# 复制可执行程序到技能目录(按平台替换文件名)
#   Linux:   FFReader-x86_64.AppImage
#   macOS:   FFReader.app(或 FFReader.app/Contents/MacOS/FFReader)
#   Windows: FFReaderCli-x64.exe(并把 config/ 目录复制到同级)

重启 Claude Code 后,输入 /ffreader 显式触发,或直接用自然语言描述(如「把 OFD_XXX.txt 转成 csv」)自动匹配该技能。

WorkBuddy

技能目录(用户级):

平台 路径
macOS / Linux ~/.workbuddy/skills/ffreader/
Windows C:\Users\<用户名>\.workbuddy\skills\ffreader

注:WorkBuddy 不同版本技能目录路径可能略有差异,以界面中「技能管理」显示的本地技能目录为准;项目级也可放入 .codebuddy/skills/

安装步骤与 Claude Code 相同:创建 ffreader 目录 → 放入 SKILL.md → 放入对应平台可执行程序(Windows 同时放 config/)。重启 WorkBuddy 后,输入 @ffreader 显式触发,或自然语言描述自动匹配。

常见问题

  • 技能装了不生效? 确认 SKILL.md 直接位于 ffreader/ 目录下(不要多套一层),目录名与 frontmatter 的 nameffreader)一致;重启 AI 工具后重试。
  • Windows 找不到可执行程序? 确认 FFReaderCli-*.execonfig/ 在同级目录。
  • 可执行程序放技能目录还是放 PATH? 放技能目录最省心(免配置)。若 FFReader 已单独安装,也可在对话中直接告知 AI 程序所在路径,AI 会按「用户指定目录」查找。