在Docker容器(Alpine)中用Python读取.accdb数据库

3 投票
2 回答
125 浏览
提问于 2025-04-13 21:27

我正在尝试在我的Python 3.11应用程序中读取一个本地的.accdb文件,但一直失败。这个应用程序是在一个python:3.11-alpine的容器里运行的。

我的Dockerfile执行时没有错误:

FROM python:3.11-alpine

EXPOSE 5001
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN apk update && apk add --no-cache gcc g++ musl-dev unixodbc-dev flex bison gawk
COPY requirements.txt .
RUN python -m pip install -r requirements.txt
RUN apk add --no-cache git autoconf automake libtool gettext-dev make
RUN git clone https://github.com/mdbtools/mdbtools.git
WORKDIR /mdbtools
RUN autoreconf -i -f
RUN ./configure --with-unixodbc=/usr --disable-dependency-tracking
RUN make
RUN make install
RUN echo -e "\n[MDBTools]\nDescription=MDBTools Driver\nDriver=/usr/local/lib/odbc/libmdbodbc.so" >> /etc/odbcinst.ini
RUN apk add --no-cache nano

WORKDIR /app
COPY . /app
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
USER appuser

CMD ["python", "server.py"]

我的Python脚本是accdb_test.py

import pyodbc
import argparse

parser = argparse.ArgumentParser(description='Connect to an Access database.')
parser.add_argument('db_path', type=str, help='The path to the Access database')

args = parser.parse_args()

conn_str = (
    r'DRIVER={MDBTools};'
    r'DBQ=' + args.db_path + ';'
)
try:
    conn = pyodbc.connect(conn_str)
    print("Connection successful!")
except pyodbc.Error as e:
    print("Failed to connect to the database:", e)

我构建了这个容器,连接到它的终端,然后运行这个脚本,结果是:

/app $ python accdb_test.py /app/input_examples/caesar/MODEL_13-16_R01.ACCDB
['MDBTools']
File not found
File not found
Unable to locate database
Failed to connect to the database: ('HY000', 'The driver did not supply an error!')

我检查过了,.accdb文件的路径是正确的:

/app $ ls -l /app/input_examples/caesar/MODEL_13-16_R01.ACCDB
-rwxrwxrwx    1 appuser  root      47116288 Mar 18 09:29 /app/input_examples/caesar/MODEL_13-16_R01.ACCDB

2 个回答

1

原来的Dockerfile构建mdbtools的方式导致了g_strsplit()这个函数出问题。这个函数在这里被使用:点击查看。下面这个Dockerfile的修改可以让g_strsplit()正常工作,并且在DBQ=后面有分号时,.connect()也不会出错。

FROM python:3.11-alpine

RUN apk update
RUN apk --no-cache add \
    build-base \
    autoconf \
    automake \
    glib \
    glib-dev \
    libc-dev \
    libtool \
    bison \
    flex-dev \
    unixodbc \
    unixodbc-dev \
    git

RUN python -m pip install pyodbc

RUN git clone https://github.com/mdbtools/mdbtools.git
WORKDIR /mdbtools
RUN autoreconf -i -f
RUN ./configure --with-unixodbc=/usr --disable-man
RUN make
RUN make install

RUN echo -e "\n[MDBTools]\nDescription=MDBTools Driver\nDriver=/usr/local/lib/odbc/libmdbodbc.so" >> /etc/odbcinst.ini

WORKDIR /app
COPY accdb_test.py accdb_test.py
COPY ansi92test.accdb ansi92test.accdb
3

根据我的理解,mdbtools 需要一个包含两个部分的连接字符串,并且中间只用一个分号。

因为你在连接字符串的末尾加了一个分号,所以它在寻找一个名为 /app/input_examples/caesar/MODEL_13-16_R01.ACCDB; 的文件,但找不到这个文件。

你可以在 这里 查看源代码,它把连接字符串分成最多两个部分,任何额外的分隔符和部分都会被加到文件名里。

解决方法很简单:去掉分号:

conn_str = (
    r'DRIVER={MDBTools};'
    r'DBQ=' + args.db_path
)

撰写回答