如何使用 Python 找到 Windows 通用应用程序数据文件夹?

Posted

技术标签:

【中文标题】如何使用 Python 找到 Windows 通用应用程序数据文件夹?【英文标题】:How do I find the Windows common application data folder using Python? 【发布时间】:2009-03-09 15:48:55 【问题描述】:

我希望我的应用程序存储一些数据以供所有用户访问。使用 Python,我怎样才能找到数据应该去哪里?

【问题讨论】:

这是用于什么操作系统的? @tgray,在问题标题中。 这有点尴尬…… 【参考方案1】:

如果您不想为诸如 winpaths 之类的第三方模块添加依赖项,我建议使用 Windows 中已有的环境变量:

What environment variables are available in Windows?

具体来说,您可能希望ALLUSERSPROFILE 获取通用用户配置文件文件夹的位置,即应用程序数据目录所在的位置。

例如:

C:\> python -c "import os; print os.environ['ALLUSERSPROFILE']"
C:\Documents and Settings\All Users

编辑:查看 winpaths 模块,它使用 ctypes,因此如果您只想使用代码的相关部分而不安装 winpath,您可以使用它(显然,为简洁起见省略了一些错误检查)。

import ctypes
from ctypes import wintypes, windll

CSIDL_COMMON_APPDATA = 35

_SHGetFolderPath = windll.shell32.SHGetFolderPathW
_SHGetFolderPath.argtypes = [wintypes.HWND,
                            ctypes.c_int,
                            wintypes.HANDLE,
                            wintypes.DWORD, wintypes.LPCWSTR]


path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
result = _SHGetFolderPath(0, CSIDL_COMMON_APPDATA, 0, 0, path_buf)
print path_buf.value

示例运行:

C:\> python get_common_appdata.py
C:\Documents and Settings\All Users\Application Data

【讨论】:

如果用户使用的是非英语版本的 Windows 怎么办? ALLUSERSPROFILE 是否仍然适用? @Out Into Space - 至少在意大利语版本的 Windows 上是这样,但不确定其他非英语版本。 那么相关的地方是什么?是_SHGetFolderPath 提供的C:\Documents and Settings\All Users\Application Data\MySoftware 还是os.environ['ALLUSERSPROFILE'] 提供的C:\Documents and Settings\All Users\MySoftware?需要`\Application Data\`(第一个解决方案)还是不需要(第二个解决方案)? 使用ctypes.create_unicode_buffer,它适用于 PY2 和 PY3。由于使用了from ctypes import *,它只是在PY2的wintypes中意外出现。 @Basj,程序应该使用SHGetFolderPathW"%ALLUSERSPROFILE%\Application Data" 只能在批处理文件中使用。 Vista+ 中的首选环境变量是ProgramDataPublic【参考方案2】:

来自http://snipplr.com/view.php?codeview&id=7354

homedir = os.path.expanduser('~')

# ...works on at least windows and linux. 
# In windows it points to the user's folder 
#  (the one directly under Documents and Settings, not My Documents)


# In windows, you can choose to care about local versus roaming profiles.
# You can fetch the current user's through PyWin32.
#
# For example, to ask for the roaming 'Application Data' directory:
#  (CSIDL_APPDATA asks for the roaming, CSIDL_LOCAL_APPDATA for the local one)
#  (See microsoft references for further CSIDL constants)
try:
    from win32com.shell import shellcon, shell            
    homedir = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0)

except ImportError: # quick semi-nasty fallback for non-windows/win32com case
    homedir = os.path.expanduser("~")

要获取所有用户而不是当前用户的 app-data 目录,只需使用 shellcon.CSIDL_COMMON_APPDATA 而不是 shellcon.CSIDL_APPDATA

【讨论】:

OP 要求所有用户都可以访问数据 @Jason S:我已经为所有用户添加了一个关于应用数据的注释。 常量值对应于 MS 网站中记录的 Environment.SpecialFolder 枚举:docs.microsoft.com/en-us/dotnet/api/…【参考方案3】:

看看http://ginstrom.com/code/winpaths.html。这是一个简单的模块,它将检索 Windows 文件夹信息。模块实现get_common_appdata 获取所有用户的App Data文件夹。

【讨论】:

+1 这看起来很有用,谢谢,但是 Jays 的回答让我得到了我想要的,没有额外的依赖【参考方案4】:

您可以使用os 模块中的os.environ 字典访问所有操作系统环境变量。但是,从该字典中选择使用哪个键可能很棘手。特别是,在使用这些路径时,您应该注意国际化(即非英语)版本的 Windows。

os.environ['ALLUSERSPROFILE'] 应该为您提供计算机上所有用户的根目录,但之后请注意不要硬编码子目录名称,如“应用程序数据”,因为这些目录在非英语版本的 Windows 上不存在.就此而言,您可能想研究一下哪些版本的 Windows 可以设置 ALLUSERSPROFILE 环境变量(我自己也不知道——它可能是通用的)。

我这里的 XP 机器有一个 COMMONAPPDATA 环境变量指向 All Users\Application Data 文件夹,但是我的 Win2K3 系统没有这个环境变量。

【讨论】:

【参考方案5】:

由于与非美国版本的 Windows 和 Vista 不兼容,先前的答案被删除。

编辑:要扩展 Out Into Space 的答案,您可以使用 winpaths.get_common_appdata 函数。您可以使用easy_install winpaths 或转到pypi 页面http://pypi.python.org/pypi/winpaths/ 并下载.exe 安装程序来获取winpath。

【讨论】:

不幸的是,这在非英语操作系统上是行不通的。 能否说得更具体一些? 我相信他的意思是“文档和设置”已本地化为 XP 的非英文副本。此外,可以通过注册表更改此文件夹的位置。最后,Vista 将这个文件夹命名为“Users”。教训:不要硬编码。 但是使用 winpaths.get_common_appdata 使用注册表值,对吗?这种方法应该是跨语言的。 我建议删除答案的第一部分,硬编码这个值对于 vista 或任何非英语 XP 来说都是错误的【参考方案6】:

由于 SHGetFolderPath 已被弃用,您也可以在 Vista 和更新版本中使用 SHGetKnownFolderPath。这也使您可以查找比 SHGetFolderPath 更多的路径。这是一个精简的示例(完整代码available on Gist):

import ctypes, sys
from ctypes import windll, wintypes
from uuid import UUID

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

    def __init__(self, uuid_):
        ctypes.Structure.__init__(self)
        self.Data1, self.Data2, self.Data3, self.Data4[0], self.Data4[1], rest = uuid_.fields
        for i in range(2, 8):
            self.Data4[i] = rest>>(8 - i - 1)*8 & 0xff

class FOLDERID:     # [2]
    LocalAppData            = UUID('F1B32785-6FBA-4FCF-9D55-7B8E7F157091')
    LocalAppDataLow         = UUID('A520A1A4-1780-4FF6-BD18-167343C5AF16')
    RoamingAppData          = UUID('3EB685DB-65F9-4CF6-A03A-E3EF65729F3D')

class UserHandle:   # [3]
    current = wintypes.HANDLE(0)
    common  = wintypes.HANDLE(-1)

_CoTaskMemFree = windll.ole32.CoTaskMemFree     # [4]
_CoTaskMemFree.restype= None
_CoTaskMemFree.argtypes = [ctypes.c_void_p]

_SHGetKnownFolderPath = windll.shell32.SHGetKnownFolderPath     # [5] [3]
_SHGetKnownFolderPath.argtypes = [
    ctypes.POINTER(GUID), wintypes.DWORD, wintypes.HANDLE, ctypes.POINTER(ctypes.c_wchar_p)
] 

class PathNotFoundException(Exception): pass

def get_path(folderid, user_handle=UserHandle.common):
    fid = GUID(folderid) 
    pPath = ctypes.c_wchar_p()
    S_OK = 0
    if _SHGetKnownFolderPath(ctypes.byref(fid), 0, user_handle, ctypes.byref(pPath)) != S_OK:
        raise PathNotFoundException()
    path = pPath.value
    _CoTaskMemFree(pPath)
    return path

common_data_folder = get_path(FOLDERID.RoamingAppData)

# [1] http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
# [2] http://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx
# [3] http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188.aspx
# [4] http://msdn.microsoft.com/en-us/library/windows/desktop/ms680722.aspx
# [5] http://www.themacaque.com/?p=954

【讨论】:

以上是关于如何使用 Python 找到 Windows 通用应用程序数据文件夹?的主要内容,如果未能解决你的问题,请参考以下文章

Windows 通用应用程序:无法加载文件或程序集 - 找到的程序集的清单定义与程序集引用不匹配

使用 Anaconda Python 的 PyQt Windows 安装程序 - 未找到 PyQt4;如何进行故障排除?

Python邮件发送脚本(Linux,Windows)通用

如何使用通用 Windows 平台 (UWP) 应用程序执行进程命令(或类似命令)?

如何通过 python/pyqt 创建 Windows 7 跳转列表?

通用 Windows (UWP) 范围滑块