python — поиск папки «Загрузки» пользователя

Я уже нашел этот вопрос, который предлагает использовать os.path.expanduser(path) для получения домашнего каталога пользователя .

Я хотел бы добиться того же с папкой «Загрузки». Я знаю, что это возможно в C#, но я новичок в Python и не не знаю, возможно ли это и здесь, предпочтительно независимо от платформы (Windows, Ubuntu).

Я знаю, что мог бы сделать download_folder = os.path.expanduser("~")+"/Downloads/", но (по крайней мере, в Windows) можно изменить папку загрузки по умолчанию.


person Markus Weninger    schedule 07.03.2016    source источник
comment
Имея достаточно ctypes-foo, вы можете адаптировать специфичный для Windows код в этом ответе к Python (с откатом к os.expanduser(...) на не -платформы Windows). Вот пример. Обратите внимание, однако, что каталог Downloads не является независимой от платформы концепцией. Вполне возможно встретить системы Linux, в которых его нет, поэтому обязательно создайте его, если он не существует.   -  person user4815162342    schedule 07.03.2016
comment
@user4815162342: Хорошо, спасибо за совет с a "Downloads" directory is not a platform-independent concept.!   -  person Markus Weninger    schedule 07.03.2016


Ответы (3)


Правильное расположение папок Windows в Python является довольно сложной задачей. Согласно ответам, касающимся технологий разработки Microsoft, таких как этот, они должны быть получены с помощью Vista API известных папок. Этот API не включен в стандартную библиотеку Python (хотя существует ошибка 2008 года, запрашивающая его), но в любом случае для доступа к нему можно использовать модуль ctypes.

Адаптация приведенного выше ответа для использования идентификатора папки для загрузки >показанный здесь, и объединение его с вашим существующим кодом Unix должно привести к коду, который выглядит следующим образом:

import os

if os.name == 'nt':
    import ctypes
    from ctypes import windll, wintypes
    from uuid import UUID

    # ctypes GUID copied from MSDN sample code
    class GUID(ctypes.Structure):
        _fields_ = [
            ("Data1", wintypes.DWORD),
            ("Data2", wintypes.WORD),
            ("Data3", wintypes.WORD),
            ("Data4", wintypes.BYTE * 8)
        ] 

        def __init__(self, uuidstr):
            uuid = UUID(uuidstr)
            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

    SHGetKnownFolderPath = windll.shell32.SHGetKnownFolderPath
    SHGetKnownFolderPath.argtypes = [
        ctypes.POINTER(GUID), wintypes.DWORD,
        wintypes.HANDLE, ctypes.POINTER(ctypes.c_wchar_p)
    ]

    def _get_known_folder_path(uuidstr):
        pathptr = ctypes.c_wchar_p()
        guid = GUID(uuidstr)
        if SHGetKnownFolderPath(ctypes.byref(guid), 0, 0, ctypes.byref(pathptr)):
            raise ctypes.WinError()
        return pathptr.value

    FOLDERID_Download = '{374DE290-123F-4565-9164-39C4925E467B}'

    def get_download_folder():
        return _get_known_folder_path(FOLDERID_Download)
else:
    def get_download_folder():
        home = os.path.expanduser("~")
        return os.path.join(home, "Downloads")

Более полный модуль для получения известных папок из Python доступен на github.

person user4815162342    schedule 07.03.2016
comment
Спасибо за подробное расследование и ссылку на проблему. - person Markus Weninger; 07.03.2016
comment
@MarkusWeninger Вы также можете взглянуть на эту более полную оболочку для SHGetKnownFolderPath. - person user4815162342; 08.03.2016
comment
Спасибо! Я буду смотреть в него. get_download_folder() в настоящее время аварийно завершает работу со следующей ошибкой. File ".\downloadfolders.py", line 34, in _get_known_folder_path if SHGetKnownFolderPath(ctypes.byref(guid), 0, 0, ctypes.byref(pathptr)): ctypes.ArgumentError: argument 4: <class 'TypeError'>: expected LP_c_char_p instance instead of pointer to c_wchar_p - person Markus Weninger; 08.03.2016
comment
Да, print(get_download_folder()) теперь печатает мою папку загрузки (используя Windows 10). Еще раз большое спасибо, жаль, что я не могу снова проголосовать;) - person Markus Weninger; 08.03.2016
comment
@MarkusWeninger Пожалуйста. Ответ изменен, чтобы удалить непроверенное утверждение. :) - person user4815162342; 09.03.2016

Это довольно простое решение (расширенное из этот пост на Reddit) сработало для меня.

import os

def get_download_path():
    """Returns the default downloads path for linux or windows"""
    if os.name == 'nt':
        import winreg
        sub_key = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
        downloads_guid = '{374DE290-123F-4565-9164-39C4925E467B}'
        with winreg.OpenKey(winreg.HKEY_CURRENT_USER, sub_key) as key:
            location = winreg.QueryValueEx(key, downloads_guid)[0]
        return location
    else:
        return os.path.join(os.path.expanduser('~'), 'downloads')
  • GUID можно получить на сайте Microsoft KNOWNFOLDERID. документы
  • Это может быть расширено для более общей работы с другими каталогами.
person Alexander McFarlane    schedule 09.02.2018
comment
Но это найдет путь к папке загрузок локального сервера. Как найти папку загрузок клиента, если то же самое нужно сделать для веб-приложения? - person user10058776; 08.06.2021
comment
вы не можете сделать это на стороне сервера по понятным причинам — вам нужно будет встроить какой-то скрипт в ваше веб-приложение, которое запускается браузером конечного пользователя. - person Alexander McFarlane; 11.06.2021
comment
@ Александр Макфарлейн, да, узнал! - person user10058776; 12.06.2021

Для python3+ mac или linux

from pathlib import Path
path_to_download_folder = str(os.path.join(Path.home(), "Downloads"))
person Jeff WR    schedule 28.10.2019