如何检查Python中是否存在SQLite3数据库?

时间:2012-10-17 10:46:42

标签: python python-2.7 sqlite

我正在尝试在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)这样的文件操作?

6 个答案:

答案 0 :(得分:23)

在Python 2中,您必须使用os.path.isfile显式测试存在:

if os.path.isfile(db):

无法强制sqlite3.connect功能不为您创建文件。


对于那些使用Python 3.4或更高版本的用户,可以使用较新的URI路径功能在打开数据库时设置不同的模式。默认情况下,sqlite3.connect()功能会在rwc中打开数据库,即读取,写入&创建模式,因此连接到不存在的数据库将导致它被创建。

使用URI,您可以指定其他模式;如果您将其设置为rw,那么 Read&写入模式,尝试连接到不存在的数据库时会引发异常。在连接时设置uri=True标志并传入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 Recognized Query Parameters documentation

答案 1 :(得分:17)

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

答案 2 :(得分:1)

是的,有一种方法可以用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() docs声明:

  

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

     

db = sqlite3.connect(&#39; file:path / to / database?mode = ro&#39;,uri = True)

     

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

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

  

模式:模式参数可以设置为&#34; ro&#34;,&#34; rw&#34;,&#34; rwc&#34;或&# 34;存储器&#34 ;.试图将其设置为任何其他值是一个错误。如果&#34; ro&#34;指定,然后打开数据库以进行只读访问,就像在sqlite3_open_v2()的第三个参数中设置了SQLITE_OPEN_READONLY标志一样。如果mode选项设置为&#34; rw&#34;,则打开数据库以进行读写(但不是create)访问,就像设置了SQLITE_OPEN_READWRITE(但不是SQLITE_OPEN_CREATE)一样。价值&#34; rwc&#34;相当于同时设置SQLITE_OPEN_READWRITE和SQLITE_OPEN_CREATE。如果mode选项设置为&#34; memory&#34;然后使用永远不会从磁盘读取或写入的纯内存数据库。为mode参数指定一个值的错误,该值的限制性比第三个参数中传递给sqlite3_open_v2()的标志的限制要小。

     

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=':/')

答案 3 :(得分:0)

这是一个基于 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.")

答案 4 :(得分: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数据库创建的文件长度为0。
  • 其他读取文件头的示例在Python 3.7.7中返回字节,而不是字符串,因此比较将失败。
  • 使用sqlite3.connect(dburl, uri=True)的示例在Python 3.7.7中对我不起作用,因为它会带来误报。

答案 5 :(得分:-1)

我在脚本的开头使用了如下所示的函数,以便我可以尝试找出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