跳转到内容

Python 读取 DBF

处理遗留的 .dbf 文件,通常需要拆分使用两个专门的库:

  • 读取:推荐使用 dbfread (仅读,但性能和兼容性较好)。
  • 写入:推荐使用 dbf
Terminal window
pip install dbfread dbf pandas dask

在处理国内历史系统的 DBF 文件时,最容易崩溃的环节是中文字符编码。推荐使用级联 Try-Except 策略,从最常见的 cp936 (GBK) 逐步降级尝试:

import dask.dataframe as dd
from dbfread import DBF
import pandas as pd
def read_dbf_file(file_path):
"""安全读取 DBF 文件并转化为 Dask/Pandas DataFrame"""
try:
# 首选尝试:GBK 编码
dbf_data = DBF(file_path, encoding='cp936')
df = pd.DataFrame(iter(dbf_data))
except Exception as e:
try:
# 降级一:最新版的 GB18030 扩展编码
dbf_data = DBF(file_path, encoding='gb18030')
df = pd.DataFrame(iter(dbf_data))
except Exception as e1:
# 降级二:UTF-8 编码
dbf_data = DBF(file_path, encoding='utf-8')
df = pd.DataFrame(iter(dbf_data))
# 转为 dask dataframe 处理大数据量
return dd.from_pandas(df)

写入 DBF 文件时,必须严格定义各列的内部数据类型与长度(如 C(20) 代表 20 字节字符串,N(6,2) 代表总长 6 位且含 2 位小数的数字)。

import dbf
def write_dbf_file(df, dest_path):
"""将 DataFrame 严格按字段规范写入 DBF 文件"""
# 1. 字段类型映射字典 (C: Character, N: Numeric, D: Date)
type_map = {
'科目': "C(20)", '学号': "C(20)", '原始成绩': "N(6,2)"
}
# 2. 列名映射字典 (DBF 列名严格受限于 10 个字节,尽量用短拼音)
name_map = {
'科目': "kmmc", '学号': "zkzh", '原始成绩': "yscj"
}
# 执行列名替换
new_df = df.rename(columns=name_map)
# 3. 构造构建 DBF 表所需的字段声明列表
# 示例: ["kmmc C(20)", "zkzh C(20)", "yscj N(6,2)"]
fields = [f"{name_map[col]} {type_map[col]}" for col in df.columns]
# 4. 创建并打开 DBF 表
# db3 格式最通用。注意:为了兼容特殊中文字符,写入时强烈建议使用 utf8
table = dbf.Table(dest_path, fields, dbf_type='db3', codepage="utf8")
table.open(dbf.READ_WRITE)
# 5. 遍历插入记录
for row in new_df.to_dict(orient='records'):
table.append(row)
table.close()