代码之家  ›  专栏  ›  技术社区  ›  David Sykes

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

  •  29
  • David Sykes  · 技术社区  · 17 年前

    我希望我的应用程序存储一些数据供所有用户访问。使用Python,我如何找到数据应该放在哪里?

    6 回复  |  直到 14 年前
        1
  •  42
  •   Jay    17 年前

    如果不想为第三方模块(如WinPath)添加依赖项,我建议使用Windows中已有的环境变量:

    特别是你可能想要的 ALLUSERSPROFILE

    例如。:

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

    :查看winpath模块,它使用的是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
    
        2
  •  15
  •   dbr    14 年前

    从…起 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("~")
    

    要获取所有用户(而不是当前用户)的应用程序数据目录,只需使用 shellcon.CSIDL_COMMON_APPDATA 而不是 shellcon.CSIDL_APPDATA .

        3
  •  10
  •   Robert S.    17 年前

    看看 http://ginstrom.com/code/winpaths.html get_common_appdata 获取所有用户的应用程序数据文件夹。

        4
  •  3
  •   Jeff    17 年前

    您可以使用 os.environ 词典 os 单元不过,从字典中选择要使用的键可能很棘手。特别是,在使用这些路径时,您应该注意Windows的国际化(即非英语)版本。

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

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

        5
  •  3
  •   tgray    17 年前

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

    要扩展到空间的答案,可以使用 winpaths.get_common_appdata 作用您可以使用 easy_install winpaths http://pypi.python.org/pypi/winpaths/ ,并下载.exe安装程序。

        6
  •  1
  •   Michael Kropat    12 年前

    自从 SHGetFolderPath 已弃用,您也可以使用 SHGetKnownFolderPath 在Vista和更新版本中。这还允许您查找比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
    
    推荐文章