web-dev-qa-db-ja.com

Pythonを使用してWindows共通アプリケーションデータフォルダーを見つけるにはどうすればよいですか?

すべてのユーザーがアクセスできるように、アプリケーションにいくつかのデータを保存します。 Pythonを使用して、データの移動先を見つけるにはどうすればよいですか?

29
David Sykes

Winpathsなどのサードパーティモジュールの依存関係を追加したくない場合は、Windowsですでに利用可能な環境変数を使用することをお勧めします。

具体的には、ALLUSERSPROFILEに、アプリケーションデータディレクトリが存在する共通のユーザープロファイルフォルダの場所を取得することをお勧めします。

例えば。:

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

[〜#〜] edit [〜#〜]: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
39
Jay

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

現在のユーザーではなく、すべてのユーザーのapp-dataディレクトリを取得するには、shellcon.CSIDL_COMMON_APPDATAではなくshellcon.CSIDL_APPDATAを使用します。

13
user175897

http://ginstrom.com/code/winpaths.html をご覧ください。これは、Windowsフォルダー情報を取得する単純なモジュールです。モジュールはget_common_appdataを実装して、すべてのユーザーのApp Dataフォルダーを取得します。

10
Robert S.

osモジュールのos.environ辞書を使用して、すべてのOS環境変数にアクセスできます。ただし、その辞書から使用するキーを選択するのは難しいかもしれません。特に、これらのパスを使用するときは、Windowsの国際化された(英語以外の)バージョンに注意する必要があります。

os.environ['ALLUSERSPROFILE']は、コンピューター上のすべてのユーザーのルートディレクトリを提供しますが、英語以外のバージョンのWindowsにはこれらのディレクトリが存在しないため、 "Application Data"などのサブディレクトリ名をハードコーディングしないように注意してください。さらに言えば、ALLUSERSPROFILE環境変数が設定されると予想できるWindowsのバージョンについて調査する必要があるかもしれません(私自身はわかりません-それは普遍的かもしれません)。

私のXPここのマシンには、All Users\Application Dataフォルダを指すCOMMONAPPDATA環境変数がありますが、Win2K3システムにはこの環境変数がありません。

3
Jeff

以前の回答は、米国以外のバージョンのWindowsおよびVistaとの互換性がないため削除されました。

EDIT:Out Into Spaceの答えを拡張するには、winpaths.get_common_appdata関数を使用します。 easy_install winpathsを使用するか、pypiページ http://pypi.python.org/pypi/winpaths/ に移動し、.exeインストーラーをダウンロードすることで、winpathsを取得できます。

3
tgray

SHGetFolderPath は非推奨であるため、Vista以降では SHGetKnownFolderPath も使用できます。これにより、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
1
Michael Kropat