web-dev-qa-db-fra.com

Comment trouver le dossier de données d'application commune de Windows à l'aide de Python?

Je souhaite que mon application stocke des données accessibles à tous les utilisateurs. En utilisant Python, comment puis-je trouver où les données doivent aller?

29
David Sykes

Si vous ne voulez pas ajouter de dépendance pour un module tiers comme winpaths, je recommanderais d'utiliser les variables d'environnement déjà disponibles dans Windows:

Plus précisément, vous souhaitez probablement que ALLUSERSPROFILE obtienne l'emplacement du dossier de profil utilisateur commun, où se trouve le répertoire Application Data.

par exemple.:

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

[~ # ~] edit [~ # ~] : En regardant le module winpaths, il utilise des ctypes donc si vous voulez simplement utiliser la partie pertinente de le code sans installer winpath, vous pouvez l'utiliser (évidemment une vérification d'erreur omise pour plus de brièveté).

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

Exemple d'exécution:

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

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

Pour obtenir le répertoire app-data pour tous les utilisateurs, plutôt que pour l'utilisateur actuel, utilisez simplement shellcon.CSIDL_COMMON_APPDATA au lieu de shellcon.CSIDL_APPDATA.

13
user175897

Jetez un œil à http://ginstrom.com/code/winpaths.html . Il s'agit d'un module simple qui récupérera les informations du dossier Windows. Le module implémente get_common_appdata pour obtenir le dossier App Data pour tous les utilisateurs.

10
Robert S.

Vous pouvez accéder à toutes vos variables d'environnement OS en utilisant le os.environ dictionnaire dans le module os. Cependant, choisir la clé à utiliser dans ce dictionnaire peut être délicat. En particulier, vous devez rester informé des versions internationalisées (c'est-à-dire non anglaises) de Windows lorsque vous utilisez ces chemins.

os.environ['ALLUSERSPROFILE'] devrait vous fournir le répertoire racine de tous les utilisateurs de l'ordinateur, mais attention à ne pas coder en dur les noms de sous-répertoires tels que "Application Data", car ces répertoires n'existent pas sur les versions non anglaises de Windows. D'ailleurs, vous voudrez peut-être faire des recherches sur les versions de Windows auxquelles vous pouvez vous attendre d'avoir la variable d'environnement ALLUSERSPROFILE définie (je ne me connais pas - elle peut être universelle).

Ma machine XP ici a une variable d'environnement COMMONAPPDATA qui pointe vers le dossier All Users\Application Data, mais mon système Win2K3 n'a pas cette variable d'environnement.

3
Jeff

La réponse précédente a été supprimée en raison d'une incompatibilité avec les versions non américaines de Windows et Vista.

EDIT: Pour développer la réponse de Out Into Space, vous utiliseriez le winpaths.get_common_appdata fonction. Vous pouvez obtenir des chemins d'accès à l'aide de easy_install winpaths ou en allant à la page pypi, http://pypi.python.org/pypi/winpaths/ , et en téléchargeant le programme d'installation .exe.

3
tgray

Étant donné que SHGetFolderPath est déconseillé, vous pouvez également utiliser SHGetKnownFolderPath dans Vista et versions ultérieures. Cela vous permet également de rechercher plus de chemins que SHGetFolderPath. Voici un exemple dépouillé (code complet disponible sur 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
1
Michael Kropat