为什么os.path.expanduser不返回主目录?
我正在制作一个Python桌面应用程序,它会把日志保存为.csv文件,放在用户的Windows文档文件夹里。这个应用是用Python 2.7和Kivy 1.8.0写的,使用PyInstaller 2.1打包成Windows程序,安装程序是用Inno Setup Compiler制作的。在这篇文章中,我会把用户的真实姓名替换成USER。
我有以下几行代码:
DOCUMENTS = os.path.expanduser('~\\Documents\\')
print DOCUMENTS
with open(DOCUMENTS + 'data_log.csv', 'ab') as f:
do stuff
在我的电脑和我测试过的另一台电脑上,程序运行得很好。DOCUMENTS的值是'C:\Users\USER\Documents\'。但是,在我尝试的另外三台电脑上,DOCUMENTS的值变成了'C:\Users\USER\AppData\Roaming\SPB_16.6\Documents\'。程序在尝试创建data_log.csv时崩溃,并出现了以下错误:
IOError: [Errno 2] No such file or directory: 'C:\\Users\\USER\\AppData\Roaming\\SPB_16.6\\Documents\\data_log.csv'
首先,为什么os.path.expanduser在某些系统上会出问题,而在其他系统上却正常呢?
其次,即使它在错误的目录下,open()应该可以创建文件,如果文件不存在,那为什么会导致程序崩溃呢?
我找到了导致这个问题的原因。在大多数系统上,HOME是None,所以os.path.expanduser会使用USERPROFILE。但是在少数情况下,HOME会被设置为像C:\SPB\或者C:\Users\USER\AppData\Roaming\SPB_16.6这样的路径。我的解决办法是直接使用os.environ来访问USERPROFILE,而不是使用os.path.expanduser。
1 个回答
根据expanduser
的文档:
在Windows系统中,如果设置了HOME和USERPROFILE这两个环境变量,就会使用它们;如果没有设置,则会用HOMEPATH和HOMEDRIVE的组合。对于以~user开头的路径,它会通过去掉最后一个目录部分来处理这个用户路径。
如你所见,这段代码非常简单(用inspect
查看的结果):
def expanduser(path):
"""Expand ~ and ~user constructs.
If user or $HOME is unknown, do nothing."""
if path[:1] != '~':
return path
i, n = 1, len(path)
while i < n and path[i] not in '/\\':
i = i + 1
if 'HOME' in os.environ:
userhome = os.environ['HOME']
elif 'USERPROFILE' in os.environ:
userhome = os.environ['USERPROFILE']
elif not 'HOMEPATH' in os.environ:
return path
else:
try:
drive = os.environ['HOMEDRIVE']
except KeyError:
drive = ''
userhome = join(drive, os.environ['HOMEPATH'])
if i != 1: #~user
userhome = join(dirname(userhome), path[1:i])
return userhome + path[i:]
实际上,expanduser
本身出错的可能性不大。你需要在程序中检查这些环境变量,看看它们是否有正确的值。
import os
for var in ('HOME', 'USERPROFILE', 'HOMEPATH', 'HOMEDRIVE'):
print os.environ.get(var)
如果open
出现失败,很可能是因为你想打开的文件所在的目录不存在,或者你没有权限访问这个目录。