Как найти общую папку данных приложения Windows с помощью Python? - PullRequest
29 голосов
/ 09 марта 2009

Я бы хотел, чтобы мое приложение сохраняло некоторые данные для доступа всех пользователей. Используя Python, как я могу найти, куда должны идти данные?

Ответы [ 6 ]

39 голосов
/ 09 марта 2009

Если вы не хотите добавлять зависимость для стороннего модуля, такого как winpaths, я бы порекомендовал использовать переменные среды, уже имеющиеся в Windows:

В частности, вы, вероятно, хотите, чтобы ALLUSERSPROFILE получил местоположение общей папки профиля пользователя, в которой находится каталог Application Data.

например:

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
13 голосов
/ 19 сентября 2009

С 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.

10 голосов
/ 09 марта 2009

Взгляните на http://ginstrom.com/code/winpaths.html. Это простой модуль, который будет извлекать информацию о папке Windows. Модуль реализует get_common_appdata для получения папки данных приложения для всех пользователей.

3 голосов
/ 09 марта 2009

Вы можете получить доступ ко всем переменным среды вашей ОС, используя словарь os.environ в модуле os. Однако выбрать какой ключ использовать из этого словаря может быть сложно. В частности, при использовании этих путей вы должны знать о интернационализированных (то есть неанглийских) версиях Windows.

os.environ['ALLUSERSPROFILE'] должен предоставить вам корневой каталог для всех пользователей на компьютере, но после этого будьте осторожны, чтобы не указывать имена подкаталогов в жестком коде, такие как «Данные приложения», поскольку эти каталоги не существуют в неанглийских версиях Windows. , В связи с этим вы, возможно, захотите провести исследование о том, какие версии Windows могут иметь переменную среды ALLUSERSPROFILE (я сам не знаю - она ​​может быть универсальной).

Мой компьютер с XP здесь имеет переменную среды COMMONAPPDATA, которая указывает на папку All Users \ Application Data, но моя система Win2K3 не имеет этой переменной среды.

3 голосов
/ 09 марта 2009

Предыдущий ответ удален из-за несовместимости с неамериканскими версиями Windows и Vista.

РЕДАКТИРОВАТЬ: Чтобы расширить ответ Out Into Space, вы должны использовать winpaths.get_common_appdata функция. Вы можете получить winpaths используя easy_install winpaths или перейдя на страницу pypi, http://pypi.python.org/pypi/winpaths/, и загрузив установщик .exe.

1 голос
/ 19 ноября 2013

Поскольку SHGetFolderPath устарело, вы также можете использовать SHGetKnownFolderPath в Vista и новее. Это также позволяет вам искать больше путей, чем будет SHGetFolderPath. Вот урезанный пример (полный код доступен в 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
...