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

5
我正在制作一款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。


它在崩溃的机器和正常运行的机器之间有什么主要区别吗? - TheSoundDefense
我想不出什么。它可以在两台Windows 7上运行,但会在其他Windows 7机器和唯一可用的Windows 8机器上崩溃。用户都没有更改任何隐藏的系统设置、环境变量等。 - user268639
1个回答

2

根据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 操作失败,很可能是因为您尝试打开文件的目录不存在,或者您没有访问它的权限。


它们持有正确的值,但我仍然得到这个错误。 - user268639
@user268639 能否提供更多细节?在“坏”系统中,这些变量具体取什么值? - loopbackbee
@user268639 另外,重要的是,您是如何执行脚本的?直接从控制台吗?还是由其他应用程序启动? - loopbackbee
如果操作者没有写入权限,那么就会出现权限被拒绝的错误。 - Padraic Cunningham
我使用PyInstaller将脚本打包为Windows程序。然后,我使用Inno Setup Compiler制作了一个安装程序。该安装程序像典型的Windows程序一样安装程序,并通过桌面快捷方式启动。是的,open()必须失败,因为“坏”系统错误地指向了没有文档文件夹的目录。 - user268639
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接