【问题标题】:How to determine the Dropbox folder location programmatically?如何以编程方式确定 Dropbox 文件夹位置?
【发布时间】:2012-08-20 12:50:34
【问题描述】:

我有一个脚本供多个用户在多台计算机上运行,​​但他们的 Dropbox 文件夹并不都位于各自的主目录中。我不想在脚本中硬编码路径。我宁愿以编程方式找出路径。

欢迎提出任何建议。

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

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

【问题讨论】:

标签: python directory dropbox


【解决方案1】:

我找到了答案here。设置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])

【讨论】:

  • 在 Windows 上查找 host.db:host_db_path = os.path.join(winpaths.get_appdata(), 'Dropbox', 'host.db') 您可以使用 use ctypes directly with CSIDL_APPDATA 而不是 winpaths。在 Linux、OSX 上:host_db_path = os.path.expanduser('~/.dropbox/host.db')
  • raise RuntimeError("Config path={} doesn't exists".format(p)) 这一行给出了NameError: global name 'p' is not defined
  • 我觉得应该是raise RuntimeError("Config path={} doesn't exist".format(host_db_path))
  • dropbox_home() 函数在 Android 上不起作用。
  • Dropbox host.db 文件在最新版本中不再存在.. Grr.. 正在寻找新的解决方案。
【解决方案2】:

在 Dropbox 帮助中心有一个答案 - How can I programmatically find the Dropbox folder paths?

短版:

使用~/.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 文件夹位置,或通过配置文件对其进行配置。

    【讨论】:

    • 我确实实现了这一点,但后来我发现有些用户将他们的 Dropbox 文件夹放在了他们的主目录之外......
    • 然后简单地搜索整个文件系统。它只会搜索直到找到一个名为 Dropbox 的文件夹。我仍然认为最好的解决方案是提示用户。
    • 这将找到用户的 Dropbox 应用程序文件夹,但这不一定是 Dropbox 实际存储用户数据文件的位置(有默认值,但它是用户可定义的)。该信息存储在位于该目录中的host.db 文件中。
    【解决方案4】:

    这种基于J.F. Sebastian 建议的改编适用于我在 Ubuntu 上:

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

    并实际设置工作目录:

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

    【讨论】:

    • 仅当 Dropbox 实际安装在那里时。
    【解决方案5】:

    注意:答案对 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

    【讨论】:

      【解决方案6】:

      注意:需要 Dropbox >= 2.8

      Dropbox now stores the paths in json format in a file called info.json。它位于以下两个位置之一:

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

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

      下面代码调用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 的其他解决方案不同。

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

          这应该适用于 Win7。使用 getEnvironmentVariable("APPDATA") 代替 os.getenv('APPDATA') 支持 Unicode 文件路径 - 请参阅标题为 Problems with umlauts in python appdata environvent variable 的问题。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-04
            • 2021-11-29
            • 2012-08-23
            • 1970-01-01
            • 2013-12-12
            • 2012-01-27
            相关资源
            最近更新 更多