如何在Python中以编程方式获取Dropbox文件夹位置?

时间:2022-06-08 18:20:51

I have a script that is intended to be run by multiple users on multiple computers, and they don't all have their Dropbox folders in their respective home directories. I'd hate to have to hard code paths in the script. I'd much rather figure out the path programatically.

我有一个脚本,打算由多台计算机上的多个用户运行,并且它们的各自主目录中都没有Dropbox文件夹。我不想在脚本中硬编码路径。我更倾向于以编程方式找出路径。

Any suggestions welcome.

欢迎任何建议。

EDIT: I am not using the Dropbox API in the script, the script simply reads files in a specific Dropbox folder shared between the users. The only thing I need is the path to the Dropbox folder, as I of course already know the relative path within the Dropbox file structure.

编辑:我没有在脚本中使用Dropbox API,脚本只是读取用户之间共享的特定Dropbox文件夹中的文件。我唯一需要的是Dropbox文件夹的路径,因为我当然已经知道Dropbox文件结构中的相对路径。

EDIT: If it matters, I am using Windows 7.

编辑:如果重要,我使用的是Windows 7。

8 个解决方案

#1


15  

I found the answer here. Setting s equal to the 2nd line in ~\AppData\Roaming\Dropbox\host.db and then decoding it with base64 gives the path.

我在这里找到了答案。设置s等于〜\ 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


9  

There is an answer to this on Dropbox Help Center - How can I programmatically find the Dropbox folder paths?

Dropbox帮助中心有一个答案 - 如何以编程方式查找Dropbox文件夹路径?

Short version:

Use ~/.dropbox/info.json or %APPDATA%\Dropbox\info.json

使用〜/ .dropbox / info.json或%APPDATA%\ Dropbox \ info.json

Long version:

Access the valid %APPDATA% or %LOCALAPPDATA% location this way:

以这种方式访问​​有效的%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


1  

You could search the file system using os.walk. The Dropbox folder is probably within the home directory of the user, so to save some time you could limit your search to that. Example:

您可以使用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

Alternatively you could prompt the user for the Dropbox folder location, or make it configurable via a config file.

或者,您可以提示用户输入Dropbox文件夹位置,或者通过配置文件对其进行配置。

#4


1  

Note: answer is valid for Dropbox v2.8 and higher

注意:答案适用于Dropbox v2.8及更高版本

Windows

视窗

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

This needs jq - JSON parser utility to be installed. If you are happy user of Chocolatey package manager, just run choco install jq before.

这需要安装jq-JSON解析器实用程序。如果您是Chocolatey软件包管理器的用户,请先运行choco install jq。

Linux

Linux的

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

Just similarly to Windows install jq using package manager of your distro.

就像你使用发行版的软件包管理器安装jq一样。

#5


1  

Note: requires Dropbox >= 2.8

注意:要求Dropbox> = 2.8

Dropbox now stores the paths in json format in a file called info.json. It is located in one of the two following locations:

Dropbox现在以json格式将路径存储在名为info.json的文件中。它位于以下两个位置之一:

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

I can access the %APPDATA% environment variable in Python by os.environ['APPDATA'], however I check both that and os.environ['LOCALAPPDATA']. Then I convert the JSON into a dictionary and read the 'path' value under the appropriate Dropbox (business or personal).

我可以通过os.environ ['APPDATA']访问Python中的%APPDATA%环境变量,但我同时检查了它和os.environ ['LOCALAPPDATA']。然后我将JSON转换为字典并读取相应Dropbox(业务或个人)下的“路径”值。

Calling get_dropbox_location() from the code below will return the filepath of the business Dropbox, while get_dropbox_location('personal') will return the file path of the personal 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']

This is a pure Python solution, unlike the other solution using info.json.

这是一个纯Python解决方案,与使用info.json的其他解决方案不同。

#6


0  

One option is you could go searching for the .dropbox.cache directory which (at least on Mac and Linux) is a hidden folder in the Dropbox directory.

一种选择是你可以去搜索.dropbox.cache目录(至少在Mac和Linux上)是Dropbox目录中的隐藏文件夹。

I am fairly certain that Dropbox stores its preferences in an encrypted .dbx container, so extracting it using the same method that Dropbox uses is not trivial.

我相当确定Dropbox将其首选项存储在加密的.dbx容器中,因此使用Dropbox使用的相同方法提取它并非易事。

#7


0  

This should work on Win7. The use of getEnvironmentVariable("APPDATA") instead of os.getenv('APPDATA') supports Unicode filepaths -- see question titled Problems with umlauts in python appdata environvent variable.

这应该适用于Win7。使用getEnvironmentVariable(“APPDATA”)而不是os.getenv('APPDATA')支持Unicode文件路径 - 请参阅python appdata environvent变量中标题为变音符号问题的问题。

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()

#8


0  

This adaptation based on J.F. Sebastian's suggestion works for me on Ubuntu:

基于J.F. Sebastian建议的改编在Ubuntu上对我有用:

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

And to actually set the working directory to be there:

并实际设置工作目录:

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

#1


15  

I found the answer here. Setting s equal to the 2nd line in ~\AppData\Roaming\Dropbox\host.db and then decoding it with base64 gives the path.

我在这里找到了答案。设置s等于〜\ 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


9  

There is an answer to this on Dropbox Help Center - How can I programmatically find the Dropbox folder paths?

Dropbox帮助中心有一个答案 - 如何以编程方式查找Dropbox文件夹路径?

Short version:

Use ~/.dropbox/info.json or %APPDATA%\Dropbox\info.json

使用〜/ .dropbox / info.json或%APPDATA%\ Dropbox \ info.json

Long version:

Access the valid %APPDATA% or %LOCALAPPDATA% location this way:

以这种方式访问​​有效的%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


1  

You could search the file system using os.walk. The Dropbox folder is probably within the home directory of the user, so to save some time you could limit your search to that. Example:

您可以使用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

Alternatively you could prompt the user for the Dropbox folder location, or make it configurable via a config file.

或者,您可以提示用户输入Dropbox文件夹位置,或者通过配置文件对其进行配置。

#4


1  

Note: answer is valid for Dropbox v2.8 and higher

注意:答案适用于Dropbox v2.8及更高版本

Windows

视窗

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

This needs jq - JSON parser utility to be installed. If you are happy user of Chocolatey package manager, just run choco install jq before.

这需要安装jq-JSON解析器实用程序。如果您是Chocolatey软件包管理器的用户,请先运行choco install jq。

Linux

Linux的

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

Just similarly to Windows install jq using package manager of your distro.

就像你使用发行版的软件包管理器安装jq一样。

#5


1  

Note: requires Dropbox >= 2.8

注意:要求Dropbox> = 2.8

Dropbox now stores the paths in json format in a file called info.json. It is located in one of the two following locations:

Dropbox现在以json格式将路径存储在名为info.json的文件中。它位于以下两个位置之一:

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

I can access the %APPDATA% environment variable in Python by os.environ['APPDATA'], however I check both that and os.environ['LOCALAPPDATA']. Then I convert the JSON into a dictionary and read the 'path' value under the appropriate Dropbox (business or personal).

我可以通过os.environ ['APPDATA']访问Python中的%APPDATA%环境变量,但我同时检查了它和os.environ ['LOCALAPPDATA']。然后我将JSON转换为字典并读取相应Dropbox(业务或个人)下的“路径”值。

Calling get_dropbox_location() from the code below will return the filepath of the business Dropbox, while get_dropbox_location('personal') will return the file path of the personal 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']

This is a pure Python solution, unlike the other solution using info.json.

这是一个纯Python解决方案,与使用info.json的其他解决方案不同。

#6


0  

One option is you could go searching for the .dropbox.cache directory which (at least on Mac and Linux) is a hidden folder in the Dropbox directory.

一种选择是你可以去搜索.dropbox.cache目录(至少在Mac和Linux上)是Dropbox目录中的隐藏文件夹。

I am fairly certain that Dropbox stores its preferences in an encrypted .dbx container, so extracting it using the same method that Dropbox uses is not trivial.

我相当确定Dropbox将其首选项存储在加密的.dbx容器中,因此使用Dropbox使用的相同方法提取它并非易事。

#7


0  

This should work on Win7. The use of getEnvironmentVariable("APPDATA") instead of os.getenv('APPDATA') supports Unicode filepaths -- see question titled Problems with umlauts in python appdata environvent variable.

这应该适用于Win7。使用getEnvironmentVariable(“APPDATA”)而不是os.getenv('APPDATA')支持Unicode文件路径 - 请参阅python appdata environvent变量中标题为变音符号问题的问题。

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()

#8


0  

This adaptation based on J.F. Sebastian's suggestion works for me on Ubuntu:

基于J.F. Sebastian建议的改编在Ubuntu上对我有用:

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

And to actually set the working directory to be there:

并实际设置工作目录:

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