How do I find the Windows common application data folder using Python?

ⅰ亾dé卋堺 提交于 2019-11-27 04:12:59

If you don't want to add a dependency for a third-party module like winpaths, I would recommend using the environment variables already available in Windows:

Specifically you probably want ALLUSERSPROFILE to get the location of the common user profile folder, which is where the Application Data directory resides.

e.g.:

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

EDIT: Looking at the winpaths module, it's using ctypes so if you wanted to just use the relevant part of the code without installing winpath, you can use this (obviously some error checking omitted for brevity).

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

Example run:

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

From 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("~")

To get the app-data directory for all users, rather than the current user, just use shellcon.CSIDL_COMMON_APPDATA instead of shellcon.CSIDL_APPDATA.

Take a look at http://ginstrom.com/code/winpaths.html. This is a simple module that will retrieve Windows folder information. The module implements get_common_appdata to get the App Data folder for all users.

You can access all of your OS environment variables using the os.environ dictionary in the os module. Choosing which key to use from that dictionary could be tricky, though. In particular, you should remain aware of internationalized (i.e., non-English) versions of Windows when using these paths.

os.environ['ALLUSERSPROFILE'] should give you the root directory for all users on the computer, but after that be careful not to hard code subdirectory names like "Application Data," because these directories don't exist on non-English versions of Windows. For that matter, you may want to do some research on what versions of Windows you can expect to have the ALLUSERSPROFILE environment variable set (I don't know myself -- it may be universal).

My XP machine here has a COMMONAPPDATA environment variable which points to the All Users\Application Data folder, but my Win2K3 system does not have this environment variable.

Previous answer removed due to incompatibility with non-US versions of Windows, and Vista.

EDIT: To expand on Out Into Space's answer, you would use the winpaths.get_common_appdata function. You can get winpaths using easy_install winpaths or by going to the pypi page, http://pypi.python.org/pypi/winpaths/, and downloading the .exe installer.

Since SHGetFolderPath is deprecated, you can also use SHGetKnownFolderPath in Vista and newer. This also lets you look up more paths than SHGetFolderPath will. Here's a stripped-down example (full code 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!