【问题标题】:Python sqlite3 connect with special characters in pathPython sqlite3与路径中的特殊字符连接
【发布时间】:2016-06-20 08:54:57
【问题描述】:

我有一个使用 SQLite 数据库的 PyInstaller 编译的应用程序。在名称中带有特殊字符的用户运行该软件之前,一切正常。甚至像这样的简单代码:

import sqlite3
path = "C:\\Users\\Jøen\\test.db"

db = sqlite3.connect(path)

导致回溯:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
sqlite3.OperationalError: unable to open database file

我尝试了各种组合,包括使用chardet 检测编码,然后转换为 UTF-8,但这也不起作用。在这一点上,我所有常用的 Python 编码/解码技巧都让我失望了。

是否有人成功地在 Python 中打开了路径中包含特殊字符的 SQLite DB?

因此,如果您的用户路径中有任何国际或特殊字符,一些测试代码可能会帮助我:

import os
import sqlite3
path = os.path.expanduser("~")
sqlite3.connect(path + "\\test.db")

【问题讨论】:

  • sqlite3.connect(db) 是错字吗?我猜sqlite3.connect(path)
  • 正确。已编辑。谢谢!

标签: python python-2.7 sqlite


【解决方案1】:

我看到两个问题:

  • \t制表符\U 是 8 位十六进制数字 Unicode 字符转义的开始。
  • 您需要编码为平台文件系统编码sys.getfilesystemencoding(),在 Windows 上通常是 UTF-16(小端)或 MBCS(多字节字符集,真正的意思是 *我们支持的任何多字节编码,包括 UTF-16),但 UTF-8。或者只是传入一个 Unicode 字符串,让 Python 为您处理这个问题。

在 Python 2 上,以下应该可以工作:

path = ur"C:\Users\Jøen\test.db"

这使用 原始 unicode 字符串文字,这意味着它将 a) 不将 \t 解释为制表符,而是解释为两个单独的字符 b) 为 Python 生成一个 Unicode 字符串,然后进行编码到正确的文件系统编码。

或者,在 Windows 上,正斜杠也可以用作分隔符,或者您可以将反斜杠 加倍 以正确转义它们:

path = u"C:/Users/Jøen/test.db"
path = u"C:\\Users\\Jøen\\test.db"

在 Python 3 上,只需删除 u 并且仍然编码:

path = r"C:\Users\Jøen\test.db"

从主目录构建路径,在任何地方使用 Unicode 字符串并使用 os.path.join() 来构建路径。不幸的是,os.path.expanduser() 在 Python 2 上 支持 Unicode(请参阅 bug 28171),因此使用它需要使用 sys.getfilesystemencoding() 进行解码,但这实际上可能会失败(请参阅 Problems with umlauts in python appdata environvent variable 了解原因) .你当然可以尝试:

path = os.path.expanduser("~").decode(sys.getfilesystemencoding())
sqlite3.connect(os.path.join(path, u"test.db"))

但是,依靠检索环境变量的 Unicode 值可以确保您得到一个未损坏的值;以Problems with umlauts in python appdata environvent variable 为基础,可能看起来像:

import ctypes
import os

def getEnvironmentVariable(name):
    name= unicode(name) # make sure string argument is unicode
    n= ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
    if n==0:
        return None
    buf= ctypes.create_unicode_buffer(u'\0'*n)
    ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
    return buf.value

if 'HOME' in os.environ: 
    userhome = getEnvironmentVariable('HOME')
elif 'USERPROFILE' in os.environ:
    userhome = getEnvironmentVariable('USERPROFILE')

 sqlite3.connect(os.path.join(userhome, u"test.db"))

【讨论】:

  • 很抱歉再次从我的虚拟机输入错误。路径用斜杠双重编码。使用 ur 最终只会引发 ascii 编码问题。
  • \U 也会导致使用 python3 出现问题
  • uexpanduser 一起使用会引发编码错误:&gt;&gt;&gt; path = os.path.expanduser(u"~") Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; File "C:\Python27\lib\ntpath.py", line 311, in expanduser return userhome + path[i:] UnicodeDecodeError: 'ascii' codec can't decode byte 0xf8 in position 10: ordinal not in range(128) &gt;&gt;&gt;
  • 时间短,但这可能是旧 2.7 版本中的一个错误。将进行调查。
  • 呸,骗子。在 Python 2 中它被认为是 not a bug。我将更新为使用 sys.getdefaultencoding(),因为数据来自环境变量。
【解决方案2】:

我发现无需处理编码(我从未找到解决方案)即可实际工作的方式是使用此处的答案:

How to get Windows short file name in python?

根据我的测试,短名称似乎总是删除了编码字符。我意识到这是一个拼凑,但我找不到其他方法。

【讨论】:

    猜你喜欢
    • 2012-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多