23

我正在尝试在 Python 2.7.3 中创建一个函数来打开一个 SQLite 数据库。

这是我目前的代码:

import sqlite3 as lite
import sys

db = r'someDb.sqlite'

def opendb(db):
    try:
        conn = lite.connect(db)
    except sqlite3.Error:
        print "Error open db.\n"
        return False
    cur = conn.cursor()
    return [conn, cur]

我已经尝试了上面的代码,并且我观察到该sqlite3库会打开声明的数据库(如果存在),或者如果该数据库不存在则创建一个新数据库。

有没有办法通过方法检查数据库是否存在,sqlite3或者我必须使用文件操作os.path.isfile(path)

4

6 回答 6

34

在 Python 2 中,您必须使用以下命令显式测试是否存在os.path.isfile

if os.path.isfile(db):

无法强制该sqlite3.connect函数不为您创建文件。


对于使用 Python 3.4 或更新版本的用户,您可以使用更新的 URI 路径功能在打开数据库时设置不同的模式。该sqlite3.connect()函数默认会以Read, Write & Createrwc模式打开数据库,因此连接到不存在的数据库将导致它被创建。

使用 URI,您可以指定不同的模式;如果将其设置为rw, 即读写模式,则在尝试连接到不存在的数据库时会引发异常。uri=True连接时设置flag时可以设置不同的模式,传入一个file:URI,并mode=rw在路径中添加查询参数:

from urllib.request import pathname2url

try:
    dburi = 'file:{}?mode=rw'.format(pathname2url(db))
    conn = lite.connect(dburi, uri=True)
except sqlite3.OperationalError:
    # handle missing database case

有关接受哪些参数的更多详细信息,请参阅SQLite URI识别查询参数文档

于 2012-10-17T10:55:30.033 回答
26

os.path.isfile()只是告诉你一个文件是否存在,而不是它是否存在并且是一个 SQLite3 数据库!知道http://www.sqlite.org/fileformat.html,你可以这样做:

def isSQLite3(filename):
    from os.path import isfile, getsize

    if not isfile(filename):
        return False
    if getsize(filename) < 100: # SQLite database file header is 100 bytes
        return False

    with open(filename, 'rb') as fd:
        header = fd.read(100)

    return header[:16] == 'SQLite format 3\x00'

然后像这样使用它:

for file in files:
    if isSQLite3(file):
        print "'%s' is a SQLite3 database file" % file
    else:
        print "'%s' is not a SQLite3 database file" % file
于 2013-03-12T07:45:32.883 回答
5

是的,有一种方法可以用 Python 3.4+ 做你想做的事。

使用该sqlite3.connect()函数进行连接,但将其传递给 URI 而不是文件路径,并将其添加mode=rw到其查询字符串中。

这是一个完整的工作代码示例:

import sqlite3
con = sqlite3.connect('file:aaa.db?mode=rw', uri=True)

这将从当前文件夹中命名的文件打开现有数据库aaa.db,但如果该文件无法打开或不存在,则会引发错误:

Traceback (most recent call last):
  File "aaa.py", line 2, in <module>
    con = sqlite3.connect('file:aaa.db?mode=rw', uri=True)
sqlite3.OperationalError: unable to open database file

Python sqlite.connect() 文档指出:

如果 uri 为真,则数据库被解释为 URI。这允许您指定选项。例如,要以只读模式打开数据库,您可以使用:

db = sqlite3.connect('file:path/to/database?mode=ro', uri=True)

有关此功能的更多信息,包括已识别选项的列表,可以在SQLite URI 文档中找到。

以下是从http://www.sqlite.org/c3ref/open.html收集的所有相关 URI 选项信息的摘录:

模式:模式参数可以设置为“ro”、“rw”、“rwc”或“memory”。尝试将其设置为任何其他值是错误的。如果指定了“ro”,则打开数据库以进行只读访问,就像在 sqlite3_open_v2() 的第三个参数中设置了 SQLITE_OPEN_READONLY 标志一样。如果模式选项设置为“rw”,则打开数据库进行读写(但不是创建)访问,就像设置了 SQLITE_OPEN_READWRITE(但不是 SQLITE_OPEN_CREATE)一样。值“rwc”等效于同时设置 SQLITE_OPEN_READWRITE 和 SQLITE_OPEN_CREATE。如果模式选项设置为“内存”,则使用从不从磁盘读取或写入的纯内存数据库。

sqlite3_open_v2()接口的工作方式与sqlite3_open() 类似,只是它接受两个额外的参数来额外控制新的数据库连接。sqlite3_open_v2() 的 flags 参数可以采用以下三个值之一,可选择与 SQLITE_OPEN_NOMUTEX、SQLITE_OPEN_FULLMUTEX、SQLITE_OPEN_SHAREDCACHE、SQLITE_OPEN_PRIVATECACHE 和/或 SQLITE_OPEN_URI 标志组合:

SQLITE_OPEN_READONLY 数据库以只读模式打开。如果数据库尚不存在,则返回错误。

SQLITE_OPEN_READWRITE 如果可能,打开数据库进行读取和写入,或者仅在文件受操作系统写保护时才读取。无论哪种情况,数据库都必须已经存在,否则返回错误。

SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE 打开数据库进行读写,如果数据库不存在则创建。这是 sqlite3_open() 和 sqlite3_open16() 始终使用的行为。

为方便起见,这里还有一个 Python 3.4+ 函数,用于将常规路径转换为 ​​sqlite.connect() 可用的 URI:

import pathlib
import urllib.parse

def _path_to_uri(path):
    path = pathlib.Path(path)
    if path.is_absolute():
        return path.as_uri()
    return 'file:' + urllib.parse.quote(path.as_posix(), safe=':/')
于 2017-11-17T13:21:35.773 回答
2

这是一个基于Tom Horen 答案的分叉(使用 Python 3) ,它提供了一个比选定答案更完整和可靠的解决方案。

选择的答案不评估任何内容、标题等,以确定文件是否实际包含与 SQLite3 数据库相关的任何数据。

我试图在这里提出一些更务实的东西:

#!/usr/bin/python3

import os
import sys

if os.path.isfile('test.sqlite3'):
    if os.path.getsize('test.sqlite3') > 100:
        with open('test.sqlite3','r', encoding = "ISO-8859-1") as f:
            header = f.read(100)
            if header.startswith('SQLite format 3'):
                print("SQLite3 database has been detected.")
于 2017-09-05T07:01:37.450 回答
0

基于上面的其他几个答案。这是一个干净的解决方案,适用于Python 3.7.7

def isSqlite3Db(db):
    if not os.path.isfile(db): return False
    sz = os.path.getsize(db)

    # file is empty, give benefit of the doubt that its sqlite
    # New sqlite3 files created in recent libraries are empty!
    if sz == 0: return True

    # SQLite database file header is 100 bytes
    if sz < 100: return False
    
    # Validate file header
    with open(db, 'rb') as fd: header = fd.read(100)    

    return (header[:16] == b'SQLite format 3\x00')

用法:

if isSqlite3Db('<path_to_db>'):
    # ... <path_to_db> is a Sqlite 3 DB

笔记:

  • 检查文件大小> 100的答案不起作用,因为在最近的python中创建的新sqlite3 db创建了一个长度为0的文件。
  • 读取文件头的其他示例返回字节Python 3.7.7而不是字符串,因此比较将失败。
  • 使用的示例sqlite3.connect(dburl, uri=True)对我不起作用,Python 3.7.7因为它给出了误报。
于 2020-12-06T20:16:44.893 回答
-2

我在脚本开头使用了如下函数,以便我可以尝试找出 sqlite3 db 脚本可能无法正常工作的原因。就像评论说的那样,它使用 3 个阶段,检查路径是否存在,检查路径是否为文件,检查该文件的标头是否为 sqlite3 标头。

def checkdbFileforErrors():

    #check if path exists
    try:
        with open('/path/to/your.db'): pass
    except IOError:
        return 1

    #check if path if a file
    if not isfile('/path/to/your.db'):
        return 2

    #check if first 100 bytes of path identifies itself as sqlite3 in header
    f = open('/path/to/your.db', "rx")
    ima = f.read(16).encode('hex')
    f.close()
    #see http://www.sqlite.org/fileformat.html#database_header magic header string
    if ima != "53514c69746520666f726d6174203300": 
        return 3

    return 0
于 2013-09-27T15:19:22.427 回答