如何用64位Python与ODBC驱动读取32位.mdb文件?
解决64位环境下读取32位.mdb文件并导入PostgreSQL的方案
首先得明确你遇到的核心问题:64位的Microsoft Access ACE驱动对旧版32位Jet引擎创建的.mdb文件兼容性很差,加上注册表权限限制,导致直接用64位pyodbc连接会报错。下面给你几个实用的解决方案,优先适配QGIS插件的开发需求:
方案一:32位辅助脚本 + 64位QGIS插件(最稳妥的兼容方案)
因为QGIS是64位程序,没法直接在其环境里用32位驱动,所以我们可以拆分工作:用32位Python脚本专门读取.mdb文件并输出成中间格式(比如CSV),然后64位QGIS插件调用这个脚本,再把中间数据导入PostgreSQL。
步骤:
- 改造你的32位脚本,让它支持命令行参数(去掉GUI选择,方便插件调用):
# 32位脚本:mdb_reader.py import csv import pyodbc import sys def read_mdb_to_csv(mdb_path, table_name, output_csv, password=""): DRV = '{Microsoft Access Driver (*.mdb, *.accdb)}' try: con = pyodbc.connect(f'DRIVER={DRV};DBQ={mdb_path};PWD={password}') cur = con.cursor() cur.execute(f'SELECT * FROM {table_name}') rows = cur.fetchall() # 写入CSV并包含表头 with open(output_csv, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow([col[0] for col in cur.description]) # 写入字段名 writer.writerows(rows) cur.close() con.close() print(f"导出成功:{output_csv}") except Exception as e: print(f"错误:{str(e)}", file=sys.stderr) sys.exit(1) if __name__ == "__main__": # 命令行参数格式:python mdb_reader.py <mdb路径> <表名> <输出CSV路径> [密码] if len(sys.argv) < 4: print("使用方法:python mdb_reader.py <mdb_path> <table_name> <output_csv> [password]") sys.exit(1) mdb_path = sys.argv[1] table_name = sys.argv[2] output_csv = sys.argv[3] password = sys.argv[4] if len(sys.argv) >=5 else "" read_mdb_to_csv(mdb_path, table_name, output_csv, password)
- 在64位QGIS插件中调用这个脚本:
用Python的subprocess模块调用32位Python解释器执行上面的脚本,读取生成的CSV后导入PostgreSQL:
# 64位QGIS插件中的代码片段 import subprocess import csv import psycopg2 import os def import_mdb_to_postgres(mdb_path, table_name, pg_conn_params): # 临时CSV路径 temp_csv = "temp_mdb_export.csv" # 32位Python的路径(可让用户在插件设置中配置,适配不同环境) python_32_path = r"C:\Python38-32\python.exe" mdb_reader_script = r"插件目录下的mdb_reader.py路径" # 调用32位脚本导出CSV result = subprocess.run( [python_32_path, mdb_reader_script, mdb_path, table_name, temp_csv, "pw"], capture_output=True, text=True ) if result.returncode != 0: raise Exception(f"导出失败:{result.stderr}") # 读取CSV并导入PostgreSQL conn = psycopg2.connect(**pg_conn_params) cur = conn.cursor() # 根据表头生成建表语句(实际可根据数据类型优化) with open(temp_csv, 'r', encoding='utf-8') as f: reader = csv.reader(f) headers = next(reader) create_table_sql = f"CREATE TABLE IF NOT EXISTS {table_name} ({', '.join([f'{h} TEXT' for h in headers])})" cur.execute(create_table_sql) # 批量插入数据 insert_sql = f"INSERT INTO {table_name} VALUES ({', '.join(['%s']*len(headers))})" cur.executemany(insert_sql, reader) conn.commit() cur.close() conn.close() # 清理临时文件 os.remove(temp_csv)
这个方案完全复用你已有的32位脚本经验,且兼容所有装了32位Python和Access驱动的同事设备。
方案二:使用开源MDB Tools(无需Access驱动,跨平台)
如果不想依赖Microsoft的Access驱动,可以用MDB Tools——一个开源工具集,专门读取.mdb文件,支持64位系统,甚至跨Windows/Linux/macOS。
步骤:
- 安装MDB Tools:Windows可用Chocolatey安装
choco install mdbtools,Linux/macOS用包管理器(比如apt install mdbtools),也可下载预编译的64位版本。 - 在Python中调用MDB Tools:
- 方法一:直接调用命令行工具
mdb-export导出CSV:import subprocess temp_csv = "temp_export.csv" # 导出指定表到CSV,指定日期格式 subprocess.run( ["mdb-export", "-D", "%Y-%m-%d %H:%M:%S", mdb_path, table_name], stdout=open(temp_csv, 'w', encoding='utf-8') ) # 后续导入PostgreSQL的代码同方案一 - 方法二:用Python绑定库
pymdbtools直接读取:from pymdbtools import Mdb with Mdb(mdb_path) as mdb: table = mdb.table(table_name) headers = table.columns rows = list(table.rows) # 直接用rows数据导入PostgreSQL
- 方法一:直接调用命令行工具
这个方案无需安装Access驱动,兼容性更好,能直接在64位QGIS环境中运行,不用额外的32位脚本。
方案三:使用商业ODBC驱动(最省心的方案)
如果预算允许,可以用支持64位读取旧版.mdb的商业ODBC驱动,比如Easysoft ODBC-Access Driver或Devart ODBC Driver for Access。这类驱动专门解决64位环境下的旧Jet格式兼容性问题,安装后你几乎可以直接复用原来的pyodbc代码。
示例代码(以Easysoft为例):
import pyodbc DRV = '{Easysoft ODBC-Access Driver}' con = pyodbc.connect(f'DRIVER={DRV};DBQ={mdb_path};PWD=pw') # 后续读取和导入PostgreSQL的逻辑和你原来的代码一致
这个方案适合不想折腾代码、追求稳定的场景,但需要付费购买授权。
QGIS插件整合建议
- 在插件中添加UI界面,让用户选择.mdb文件、配置PostgreSQL连接信息、指定目标表名等。
- 对于方案一,可增加“32位Python路径配置”的设置项,方便不同同事适配自己的环境。
- 可以利用QGIS自带的PostgreSQL工具(比如
QgsVectorLayer、QgsDataSourceUri)简化数据导入,不用自己编写psycopg2的底层代码。
内容的提问来源于stack exchange,提问作者HC Pieck




