Как определить местоположение папки Dropbox программным способом? - программирование
Подтвердить что ты не робот

Как определить местоположение папки Dropbox программным способом?

У меня есть script, который предназначен для работы несколькими пользователями на нескольких компьютерах, и у них не все папки Dropbox в соответствующих домашних каталогах. Мне не хотелось бы иметь жесткие коды кода в script. Я бы скорее понял путь программно.

Любые предложения приветствуются.

EDIT: Я не использую API Dropbox API в script, script просто читает файлы в определенной папке Dropbox, совместно используемой между пользователями. Единственное, что мне нужно - это путь к папке Dropbox, поскольку я, конечно, уже знаю относительный путь в структуре файла Dropbox.

EDIT: Если это имеет значение, я использую Windows 7.

4b9b3361

Ответ 1

Я нашел ответ здесь. Установка s, равная 2-й строке в ~\AppData\Roaming\Dropbox\host.db, а затем декодирование ее с помощью base64 дает путь.

def _get_appdata_path():
    import ctypes
    from ctypes import wintypes, windll
    CSIDL_APPDATA = 26
    _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_APPDATA, 0, 0, path_buf)
    return path_buf.value

def dropbox_home():
    from platform import system
    import base64
    import os.path
    _system = system()
    if _system in ('Windows', 'cli'):
        host_db_path = os.path.join(_get_appdata_path(),
                                    'Dropbox',
                                    'host.db')
    elif _system in ('Linux', 'Darwin'):
        host_db_path = os.path.expanduser('~'
                                          '/.dropbox'
                                          '/host.db')
    else:
        raise RuntimeError('Unknown system={}'
                           .format(_system))
    if not os.path.exists(host_db_path):
        raise RuntimeError("Config path={} doesn't exists"
                           .format(host_db_path))
    with open(host_db_path, 'r') as f:
        data = f.read().split()

    return base64.b64decode(data[1])

Ответ 2

В Справочном центре Dropbox есть ответ - Как я могу программно найти пути к папке Dropbox?

Краткая версия:

Используйте ~/.dropbox/info.json или %APPDATA%\Dropbox\info.json

Длинная версия:

Доступ к допустимому местоположению %APPDATA% или %LOCALAPPDATA% таким образом:

import os
from pathlib import Path
import json

try:
    json_path = (Path(os.getenv('LOCALAPPDATA'))/'Dropbox'/'info.json').resolve()
except FileNotFoundError:
    json_path = (Path(os.getenv('APPDATA'))/'Dropbox'/'info.json').resolve()

with open(str(json_path)) as f:
    j = json.load(f)

personal_dbox_path = Path(j['personal']['path'])
business_dbox_path = Path(j['business']['path'])

Ответ 3

Вы можете выполнить поиск в файловой системе с помощью os.walk. Папка Dropbox, вероятно, находится в домашнем каталоге пользователя, поэтому для экономии времени вы можете ограничить свой поиск. Пример:

import os
dropbox_folder = None

for dirname, dirnames, filenames in os.walk(os.path.expanduser('~')):
    for subdirname in dirnames:
        if(subdirname == 'Dropbox'):
            dropbox_folder = os.path.join(dirname, subdirname)
            break
    if dropbox_folder:
        break

# dropbox_folder now contains the full path to the Dropbox folder, or
# None if the folder wasn't found

В качестве альтернативы вы можете запросить у пользователя местоположение папки Dropbox или настроить его с помощью файла конфигурации.

Ответ 4

Примечание: ответ действителен для Dropbox v2.8 и выше

Windows

jq -r ".personal.path" < %APPDATA%\Dropbox\info.json

Для этого требуется jq - утилита JSON parser, которая будет установлена. Если вы счастливы использовать диспетчер пакетов Chocolatey, просто запустите choco install jq раньше.

Linux

jq -r ".personal.path" < ~/.dropbox/info.json 

Как и Windows, установите jq с помощью диспетчера пакетов вашего дистрибутива.

Ответ 5

Примечание: требуется Dropbox >= 2.8

Dropbox теперь сохраняет пути в формате json в файле с именем info.json. Он расположен в одном из следующих мест:

%APPDATA%\Dropbox\info.json
%LOCALAPPDATA%\Dropbox\info.json

Я могу получить доступ к переменной среды %APPDATA% в Python с помощью os.environ['APPDATA'], но я проверяю это и os.environ['LOCALAPPDATA']. Затем я конвертирую JSON в словарь и читаю значение 'path' в соответствующем Dropbox (бизнес или личный).

Вызов get_dropbox_location() из приведенного ниже кода вернет путь к файлу Dropbox, а get_dropbox_location('personal') вернет путь к файлу личного Dropbox.

import os
import json

def get_dropbox_location(account_type='business'):
    """
    Returns a string of the filepath of the Dropbox for this user

    :param account_type: str, 'business' or 'personal'
    """
    info_path = _get_dropbox_info_path()
    info_dict = _get_dictionary_from_path_to_json(info_path)
    return _get_dropbox_path_from_dictionary(info_dict, account_type)

def _get_dropbox_info_path():
    """
    Returns filepath of Dropbox file info.json
    """
    path = _create_dropox_info_path('APPDATA')
    if path:
        return path
    return _create_dropox_info_path('LOCALAPPDATA')

def _create_dropox_info_path(appdata_str):
    r"""
    Looks up the environment variable given by appdata_str and combines with \Dropbox\info.json

    Then checks if the info.json exists at that path, and if so returns the filepath, otherwise
    returns False
    """
    path = os.path.join(os.environ[appdata_str], r'Dropbox\info.json')
    if os.path.exists(path):
        return path
    return False

def _get_dictionary_from_path_to_json(info_path):
    """
    Loads a json file and returns as a dictionary
    """
    with open(info_path, 'r') as f:
        text = f.read()

    return json.loads(text)

def _get_dropbox_path_from_dictionary(info_dict, account_type):
    """
    Returns the 'path' value under the account_type dictionary within the main dictionary
    """
    return info_dict[account_type]['path']

Это чистое решение Python, в отличие от другого решения, используя info.json.

Ответ 6

Один из вариантов - вы можете искать каталог .dropbox.cache, который (по крайней мере, на Mac и Linux) является скрытой папкой в ​​папке Dropbox.

Я уверен, что Dropbox сохраняет свои настройки в зашифрованном контейнере .dbx, поэтому извлечение его с использованием того же метода, который использует Dropbox, не является тривиальным.

Ответ 7

Это должно работать на Win7. Использование getEnvironmentVariable("APPDATA") вместо os.getenv('APPDATA') поддерживает пути к файлам Unicode - см. Вопрос под названием Проблемы с umlauts в переменной среды python appdata.

import base64
import ctypes
import os

def getEnvironmentVariable(name):
    """ read windows native unicode environment variables """
    # (could just use os.environ dict in Python 3)
    name = unicode(name) # make sure string argument is unicode
    n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
    if not n:
        return None
    else:
        buf = ctypes.create_unicode_buffer(u'\0'*n)
        ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
        return buf.value

def getDropboxRoot():
    # find the path for Dropbox root watch folder from its sqlite host.db database.
    # Dropbox stores its databases under the currently logged in user %APPDATA% path.
    # If you have installed multiple instances of dropbox under the same login this only finds the 1st one.
    # Dropbox stores its databases under the currently logged in user %APPDATA% path.
    # usually "C:\Documents and Settings\<login_account>\Application Data"
    sConfigFile = os.path.join(getEnvironmentVariable("APPDATA"),
                               'Dropbox', 'host.db')

    # return null string if can't find or work database file.
    if not os.path.exists(sConfigFile):
        return None

    # Dropbox Watch Folder Location is base64 encoded as the last line of the host.db file.
    with open(sConfigFile) as dbxfile:
        for sLine in dbxfile:
            pass

    # decode last line, path to dropbox watch folder with no trailing slash.
    return base64.b64decode(sLine)

if __name__ == '__main__':
    print getDropboxRoot()

Ответ 8

Эта адаптация основана на J.F. Предложение Sebastian для меня работает на Ubuntu:

os.path.expanduser('~/Dropbox')

И чтобы фактически установить рабочий каталог:

os.chdir(os.path.expanduser('~/Dropbox'))