DBF导出必须先定义字段结构再写入数据,因文件头需预声明全部字段名、类型、长度,且结构与数据紧耦合;字段名≤10字节、纯ASCII、不能数字开头;类型仅支持C/N/F/D/L五种,须严格映射;中文字段名易乱码,建议用英文命名。
DBF导出时字段定义和数据写入必须分两步走
dbf格式不支持“先建表再填数据”式的动态追加,dbf 文件头里必须提前声明全部字段名、类型、长度——哪怕某列全为空。结构(schema)和数据(records)物理上紧耦合在同一个文件里,所谓“分离提取”,本质是人工拆成两阶段操作:先生成空表结构,再逐条写入数据。
- 用
dbfpy或simpledbf时,Table.create()或DbfWriter()初始化就强制要求传入完整字段列表,不能留空或后期追加 -
pyodbc+ ODBC 驱动直连 DBF 目录时,驱动会把整个 .dbf 当作只读表看待,无法绕过结构直接 dump 数据 - 跨库(比如从 PostgreSQL 导出到 DBF)时,必须先查源表
information_schema.columns或用 ORM 的__table__.columns获取字段元信息,再映射为 DBF 支持的类型(如VARCHAR → C,INTEGER → N,DATE → D)
字段类型映射错一个,DBF 就打不开或乱码
DBF 的类型系统极简且不可扩展:C(字符)、N(数字)、F(浮点)、D(日期)、L(逻辑)五种。没有布尔、JSON、TIMESTAMP、TEXT 等现代类型,也没有 null 概念——所有字段默认非空,空值靠填充空格/0/19000101 表示。
-
BOOLEAN字段必须转成L类型,值映射为True→T,False→F;若存成C会显示为 "True"/"False" 字符串,Excel 打开后识别为文本 -
NUMERIC(10,2)要写成N类型并指定field_length=10, decimal_count=2;漏设decimal_count会导致小数全截断 -
TIMESTAMP必须截断为DATE(D类型),DBF 不存时间部分;强行塞datetime对象会报ValueError: year is out of range
跨表导出要防字段名重复或非法字符
DBF 规范要求字段名 ≤10 字节、纯 ASCII、不能以数字开头、不能含空格或点号。而现代数据库常有 user_id、created_at、order.total 这类命名,直接照搬会触发 InvalidFieldNameError 或静默截断。
- 自动清洗建议:用正则
re.sub(r'[^a-zA-Z0-9_]', '_', name)替换非法字符,再用name[:10].strip('_')截断,最后确保首字符非数字(前面补_) - 多个源表导出到同一 DBF 时,注意字段名全局唯一——例如两张表都有
id,得重命名为user_id和order_id,否则dbfpy写入时会报Duplicate field name - 大小写不敏感:SQL 中的
UserId和userid在 DBF 里视为同名,合并前必须人工检查
中文字段名或数据导出后乱码?别碰 Code Page
DBF 文件头里有个 code_page 字节,决定如何解释字节流。常见误区是以为设成 936(GBK)就能显示中文字段名——但绝大多数 DBF 工具(包括 Excel、FoxPro 兼容工具)根本不读这个字段,而是按当前系统区域设置硬解码。结果就是字段名看着是乱码,但数据能对上。
- 真正稳妥的做法:字段名坚持用英文(
cust_name而非客户姓名),数据内容用 UTF-8 编码写入,然后用支持 UTF-8 的工具(如dbfread或 Python 脚本)读取 - 如果必须用中文字段名,导出后用
chcp 936 & dbfview xxx.dbf在 Windows 命令行下查看,避免用 Excel 直接双击——它默认用 ANSI 解码 -
simpledbf库默认用cp1252编码字段名,写入中文会崩;必须显式传encoding='gbk',且仅限 Windows 环境有效

















