os.path.expanduser("~") 的替代方案?

4 投票
2 回答
2277 浏览
提问于 2025-04-18 07:42

在 Python 2.7.x 版本中,os.path.expanduser("~") 这个功能在处理 Unicode 字符时出现了问题。

这意味着如果你的用户目录路径中有非 ASCII 字符(比如中文、日文等),就会报错。

你可以查看这个链接了解更多信息:http://bugs.python.org/issue13207

那么,有什么其他方法可以实现同样的功能呢?

也就是说,我怎么才能获取到用户的“主目录”路径,通常在 Windows 7 上这个路径是 C:\Users\usern-name

2 个回答

1

正如评论中提到的,你实际上需要使用WinAPI的一个调用来获取USERPROFILE这个环境变量的值:

import ctypes

buf = ctypes.create_unicode_buffer(1024)
ctypes.windll.kernel32.GetEnvironmentVariableW(u"USERPROFILE", buf, 1024)
home_dir = buf.value

或者,如果你更喜欢使用专门的shell函数:

CSIDL_PROFILE = 40
buf = ctypes.create_unicode_buffer(1024)
ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_PROFILE, None, 0, buf)
print buf.value

请注意,这两个代码片段返回的是个人资料路径,这个路径不一定和主目录路径是一样的。

2

你提到的那个错误报告里面有一个解决问题的脚本,这个脚本是直接从Win32 API获取用户的主目录信息的:

import ctypes
from ctypes import windll, wintypes

class GUID(ctypes.Structure):
    _fields_ = [
         ('Data1', wintypes.DWORD),
         ('Data2', wintypes.WORD),
         ('Data3', wintypes.WORD),
         ('Data4', wintypes.BYTE * 8)
    ]

    def __init__(self, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8):
        """Create a new GUID."""
        self.Data1 = l
        self.Data2 = w1
        self.Data3 = w2
        self.Data4[:] = (b1, b2, b3, b4, b5, b6, b7, b8)

    def __repr__(self):
        b1, b2, b3, b4, b5, b6, b7, b8 = self.Data4
        return 'GUID(%x-%x-%x-%x%x%x%x%x%x%x%x)' % (
                   self.Data1, self.Data2, self.Data3, b1, b2, b3, b4, b5, b6, b7, b8)

# constants to be used according to the version on shell32
CSIDL_PROFILE = 40
FOLDERID_Profile = GUID(0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73)

def expand_user():
    # get the function that we can find from Vista up, not the one in XP
    get_folder_path = getattr(windll.shell32, 'SHGetKnownFolderPath', None)
    if get_folder_path is not None:
        # ok, we can use the new function which is recomended by the msdn
        ptr = ctypes.c_wchar_p()
        get_folder_path(ctypes.byref(FOLDERID_Profile), 0, 0, ctypes.byref(ptr))
        return ptr.value
    else:
        # use the deprecated one found in XP and on for compatibility reasons
       get_folder_path = getattr(windll.shell32, 'SHGetSpecialFolderPathW', None)
       buf = ctypes.create_unicode_buffer(300)
       get_folder_path(None, buf, CSIDL_PROFILE, False)
       return buf.value

这个expand_user()函数只会返回当前用户的主目录。

撰写回答