【问题标题】:An alternative to os.path.expanduser("~")?os.path.expanduser("~") 的替代方案?
【发布时间】:2014-07-16 06:57:00
【问题描述】:

在 python 2.7.x 中,os.path.expanduser("~") 对于 Unicode 已损坏。

这意味着如果“~”的扩展包含非 ASCII 字符,则会出现异常。

http://bugs.python.org/issue13207

我怎样才能达到同样的效果,其他方式?

(也就是说,如何获取到用户的“家目录”的路径,在Win7上通常是C:\Users\usern-name)?

【问题讨论】:

  • os.path.expanduser("~") 在 Win7 64 位和 Python 2.7 64 位上为我工作...
  • @SaulloCastro:您的路径是否包含系统代码页之外的代码点
  • @SaulloCastro:如果您的电话有效,那么无效
  • 把你的名字改成“Mark Ørnebjerg” ;)
  • @GreenAsJade:如果您有正确的代码页,这将起作用.. :-P

标签: python windows python-2.7 unicode


【解决方案1】:

正如 cmets 中所指出的,您实际上需要一个 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

请注意,两个 sn-ps 都返回配置文件路径,这不必与主路径相同。

【讨论】:

  • 这是问题os.environ 字典包含使用系统代码页编码的字节串,如果代码点无法在该代码页中编码,Windows 会给你问号。这意味着这些环境变量包含 /????? 字符用于配置的 Windows 代码页之外的任何内容,即使文件系统使用 UTF-16 对此信息进行编码。
  • 其实我连问号都没有,我得到一个异常:File "ntpath.py", line 301, in expanduser Unicode decode error ...
  • 我想知道如果我将 b"~" 传递给 expanduser(),这是否意味着它会“正常工作”,或者这一切是否会改变是我会得到 ???而不是异常,这同样糟糕!
  • @GreenAsJade:抱歉,我正在查看ntpath.py 的当前版本;你有一个旧版本,我的分析不正确。你到底有什么版本的 Python 2.7?
  • 2.7.6,虽然该错误消息来自 2.7.2(我在收到该错误消息报告给我后升级到 2.7.6,但升级并没有解决它)
【解决方案2】:

您链接到的错误报告包含一个workaround script,它直接从 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() 函数只返回当前用户的主目录。

【讨论】:

  • 谢谢 - 我会在测试后接受答案(它在本地工作,但我没有麻烦的用户名!)。你甚至编辑了 pdb !! :)
  • 嗯 - 它有效 :) 我有点担心的一件事 - 错误报告中的进一步 cmets 提到“使用 ctypes 是有风险的”,或者类似的,并且票被关闭为“wontfix ”。他们为什么不应用你上面引用的我正在使用的补丁?
  • 错误报告大多表明他们不会修复它,因为它工作量太大。 ctypes 要求 DLL 在运行时可用,您不能在所有情况下保证; Python 开发人员更喜欢依赖可以在编译(安装)时测试的功能。
猜你喜欢
  • 1970-01-01
  • 2015-06-13
  • 2015-03-03
  • 2015-09-25
  • 2019-12-16
  • 2011-06-20
  • 2015-11-03
  • 2014-04-03
  • 2011-12-13
相关资源
最近更新 更多