为什么os.path.expanduser不返回主目录?

6 投票
1 回答
10105 浏览
提问于 2025-04-18 12:49

我正在制作一个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 个回答

3

根据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出现失败,很可能是因为你想打开的文件所在的目录不存在,或者你没有权限访问这个目录。

撰写回答