Как я могу получить местоположение папки Dropbox программно в Python?
У меня есть скрипт, который должен запускаться несколькими пользователями на нескольких компьютерах, и у них не все есть папки Dropbox в соответствующих домашних каталогах. Я не хотел бы иметь жесткие пути кода в сценарии. Я бы предпочел выяснить путь программно.
Любые предложения приветствуются.
РЕДАКТИРОВАТЬ: я не использую API-интерфейс Dropbox в сценарии, сценарий просто читает файлы в определенной папке Dropbox, разделяемой между пользователями. Единственное, что мне нужно, это путь к папке Dropbox, поскольку я, конечно, уже знаю относительный путь в файловой структуре Dropbox.
РЕДАКТИРОВАТЬ: Если это имеет значение, я использую Windows 7.
8 ответов
Я нашел ответ здесь. настройка 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])
Ответ на этот вопрос есть в Справочном центре 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'])
Примечание: ответ действителен для Dropbox v2.8 и выше
Windows
jq -r ".personal.path" < %APPDATA%\Dropbox\info.json
Для этого нужно установить утилиту парсера jq - JSON. Если вы счастливый пользователь диспетчера пакетов Chocolatey, просто запустите choco install jq
до.
Linux
jq -r ".personal.path" < ~/.dropbox/info.json
Как и в случае с Windows, установите jq, используя менеджер пакетов вашего дистрибутива.
Эта адаптация, основанная на предложении jfs, работает для меня в Ubuntu:
os.path.expanduser('~/Dropbox')
И фактически установить рабочий каталог, чтобы быть там:
os.chdir(os.path.expanduser('~/Dropbox'))
Вы можете искать файловую систему, используя 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 или настроить его с помощью файла конфигурации.
Примечание: требуется 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
,
Это должно работать на Win7. Использование getEnvironmentVariable("APPDATA")
вместо os.getenv('APPDATA')
поддерживает Unicode FilePaths - см. вопрос под названием " Проблемы с умлаутами" в переменной среды appdata python.
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's root watch folder from its sqlite host.db database.
# Dropbox stores its databases under the currently logged in user's %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's %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()
Одним из вариантов является то, что вы можете пойти в поисках .dropbox.cache
каталог, который (по крайней мере, на Mac и Linux) является скрытой папкой в каталоге Dropbox.
Я вполне уверен, что Dropbox хранит свои настройки в зашифрованном виде .dbx
контейнер, поэтому извлечение его тем же методом, который использует Dropbox, не является тривиальным.