Python sqlite3在路径中使用特殊字符连接

Python sqlite3在路径中使用特殊字符连接,python,python-2.7,sqlite,Python,Python 2.7,Sqlite,我有一个使用PyInstaller编译的应用程序,它使用sqlite数据库。在名字中有特殊字符的用户运行该软件之前,一切正常。即使是这样简单的代码: import sqlite3 path = "C:\\Users\\Jøen\\test.db" db = sqlite3.connect(path) 导致回溯: Traceback (most recent call last): File "<stdin>", line 1, in <module> sqlite

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

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
我看到两个问题:

  • \t
    是制表符,
    \U
    是8位十六进制Unicode字符转义的开始
  • 您需要编码到平台文件系统编码,在Windows上通常是UTF-16(little-endian)或MBCS(多字节字符集,真正的意思是*我们支持的任何多字节编码,包括UTF-16),但不是UTF-8。或者只是传入一个Unicode字符串,让Python为您解决这个问题
在Python2上,以下各项应该可以工作:

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"
在Python3上,只需放下
u
,仍然不编码:

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

path = os.path.expanduser("~").decode(sys.getfilesystemencoding())
sqlite3.connect(os.path.join(path, u"test.db"))
但是,取而代之的是,依赖于检索环境变量的Unicode值将确保获得一个未损坏的值;在此基础上,这可能看起来像:

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"))
我看到两个问题:

  • \t
    是制表符,
    \U
    是8位十六进制Unicode字符转义的开始
  • 您需要编码到平台文件系统编码,在Windows上通常是UTF-16(little-endian)或MBCS(多字节字符集,真正的意思是*我们支持的任何多字节编码,包括UTF-16),但不是UTF-8。或者只是传入一个Unicode字符串,让Python为您解决这个问题
在Python2上,以下各项应该可以工作:

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"
在Python3上,只需放下
u
,仍然不编码:

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

path = os.path.expanduser("~").decode(sys.getfilesystemencoding())
sqlite3.connect(os.path.join(path, u"test.db"))
但是,取而代之的是,依赖于检索环境变量的Unicode值将确保获得一个未损坏的值;在此基础上,这可能看起来像:

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"))

我发现,不必处理编码(我从来没有找到解决方案)就可以实际工作的方法是使用下面的答案:


根据我的测试,短名称似乎总是删除编码字符。我意识到这是一个难题,但我找不到另一种方法。

我发现的方法实际上可以在不必处理编码的情况下工作(我从未找到解决方案),就是使用下面的答案:


根据我的测试,短名称似乎总是删除编码字符。我意识到这是一个难题,但我找不到另一种方法。

sqlite3.connect(db)
打字错误吗?我猜是
sqlite3.connect(path)
?正确。编辑。非常感谢。
sqlite3.connect(db)
是打字错误吗?我猜是
sqlite3.connect(path)
?正确。编辑。非常感谢。很抱歉再次从我的虚拟机输入错误。路径使用斜杠进行双重编码。使用
ur
只会引发ascii编码问题。
\U
使用python3也会导致问题使用
U
expanduser
一起使用会引发编码错误:
>>path=os.path.expanduser(U“~”)回溯(最后一次调用):文件“”,第1行,文件“C:\Python27\lib\ntpath.py”,第311行,在expanduser return userhome+path[i:]UnicodeDecodeError:“ascii”编解码器无法解码第10位的字节0xf8:序号不在范围内(128)>>
时间较短,但这可能是旧版本2.7中的错误。会调查的。呸,骗子。Python 2中考虑了它。由于数据来自环境变量,我将更新为使用
sys.getdefaultencoding()
。很抱歉,我的虚拟机再次输入错误。路径使用斜杠进行双重编码。使用
ur
只会引发ascii编码问题。
\U
使用python3也会导致问题使用
U
expanduser
一起使用会引发编码错误:
>>path=os.path.expanduser(U“~”)回溯(最后一次调用):文件“”,第1行,文件“C:\Python27\lib\ntpath.py”,第311行,在expanduser return userhome+path[i:]UnicodeDecodeError:“ascii”编解码器无法解码第10位的字节0xf8:序号不在范围内(128)>>
时间较短,但这可能是旧版本2.7中的错误。会调查的。呸,骗子。Python 2中考虑了它。我将更新为使用
sys.getdefaultencoding()
,因为数据来自环境变量。