Я хочу, чтобы мое приложение сохраняло некоторые данные для доступа всех пользователей. Используя Python, как я могу найти, куда должны идти данные?
Как найти общую папку данных приложения Windows с помощью Python?
Ответ 1
Если вы не хотите добавлять зависимость для стороннего модуля, такого как winpaths, я бы рекомендовал использовать переменные среды, которые уже доступны в 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
Ответ 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 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 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
Взгляните на http://ginstrom.com/code/winpaths.html. Это простой модуль, который будет получать информацию о папке Windows. Модуль реализует get_common_appdata
, чтобы получить папку данных приложения для всех пользователей.
Ответ 4
Предыдущий ответ удален из-за несовместимости с неамериканскими версиями Windows и Vista.
РЕДАКТИРОВАТЬ:. Чтобы расширить ответ на Int Into Space, вы должны использовать
winpaths.get_common_appdata
. Вы можете получить winpath с помощью easy_install winpaths
или перейдя на страницу pypi, http://pypi.python.org/pypi/winpaths/ и загрузив установщик .exe.
Ответ 5
Вы можете получить доступ ко всем переменным среды ОС, используя словарь os.environ
в модуле os
. Выбор какой клавиши для использования из этого словаря может быть сложным. В частности, вы должны оставаться в курсе интернационализированных (то есть неанглийских) версий Windows при использовании этих путей.
os.environ['ALLUSERSPROFILE']
должен предоставить вам корневой каталог для всех пользователей на компьютере, но после этого будьте осторожны, чтобы не указывать имена подкаталогов жесткого кода, такие как "Данные приложения", поскольку эти каталоги не существуют на неанглийских версиях Windows, В этом случае вы можете провести некоторое исследование того, какие версии Windows вы можете ожидать, чтобы установить переменную среды ALLUSERSPROFILE (я сам не знаю - она может быть универсальной).
В моей машине XP есть переменная среды COMMONAPPDATA, которая указывает на папку "Все пользователи\Приложения", но моя система Win2K3 не имеет этой переменной среды.
Ответ 6
Так как 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