【问题标题】:Create missing directories in ftplib storbinary在 ftplib storbinary 中创建缺失的目录
【发布时间】:2012-05-25 13:18:29
【问题描述】:

我在 python 中使用 pycurl 通过 ftp 传输文件。我可以使用以下方法在我的远程服务器上自动创建缺少的目录:

c.setopt(pycurl.FTP_CREATE_MISSING_DIRS, 1)

由于某些原因,我不得不切换到 ftplib。但我不知道如何在这里做同样的事情。是否有任何选项可以添加到 storbinary 函数中来做到这一点?还是我必须手动创建目录?

【问题讨论】:

    标签: python pycurl ftplib


    【解决方案1】:

    FTP_CREATE_MISSING_DIRS 是一个 curl 操作 (added here)。我冒昧地猜测您必须使用 ftplib 手动执行此操作,但我很想被证明是错误的,有人吗?

    我会执行以下操作:(未经测试,需要捕获 ftplib.all_errors

    ftp = ... # Create connection
    
    # Change directories - create if it doesn't exist
    def chdir(dir): 
        if directory_exists(dir) is False: # (or negate, whatever you prefer for readability)
            ftp.mkd(dir)
        ftp.cwd(dir)
    
    # Check if directory exists (in current location)
    def directory_exists(dir):
        filelist = []
        ftp.retrlines('LIST',filelist.append)
        for f in filelist:
            if f.split()[-1] == dir and f.upper().startswith('D'):
                return True
        return False
    

    或者你可以像这样directory_exists:(有点难读?)

    # Check if directory exists (in current location)
    def directory_exists(dir):
        filelist = []
        ftp.retrlines('LIST',filelist.append)
        return any(f.split()[-1] == dir and f.upper().startswith('D') for f in filelist)
    

    【讨论】:

    • 谢谢,虽然这不是我想要的,但它是一个很好的答案。谢谢;)
    • 不,您不必手动操作。您可以直接调用 ftputil 包中的 makedirs 方法。
    • 请注意,此解决方案仅适用于顶级目录,不适用于子目录
    【解决方案2】:

    我知道这是一篇旧帖子,但我只是需要它并想出了一个非常简单的功能。我是 Python 新手,如果有任何反馈,我将不胜感激。

    from ftplib import FTP
    
    ftp = FTP('domain.com', 'username', 'password')
    
    def cdTree(currentDir):
        if currentDir != "":
            try:
                ftp.cwd(currentDir)
            except IOError:
                cdTree("/".join(currentDir.split("/")[:-1]))
                ftp.mkd(currentDir)
                ftp.cwd(currentDir)
    

    使用示例:

    cdTree("/this/is/an/example")
    

    【讨论】:

    • 非常好! dir 是一个 python 内置的,你可能想改变那个变量名......你也想捕捉特定的异常,而不是全部
    • 感谢 xApple 的反馈。我替换了 'dir' 并限制为仅捕获 IOError 异常。
    • 我想你忘了替换 dir 变量的实例。
    • 糟糕,已修复。谢谢你抓住它。现在它很完美,只需要投票即可。 :)
    • @lecnt - 更多建议:lower_case_with_underscores 是函数/变量名称的首选 - 请参阅 pep8。此外,最好使用 os.path 函数来操作路径,例如os.path.normpath(os.path.join(current_dir, '..'))
    【解决方案3】:

    我尝试将此作为评论添加到@Alex L 的答案中,但它太长了。如果要在途中创建目录,则需要在更改目录时递归下降。例如

    def chdir(ftp, directory):
        ch_dir_rec(ftp,directory.split('/')) 
    
    # Check if directory exists (in current location)
    def directory_exists(ftp, directory):
        filelist = []
        ftp.retrlines('LIST',filelist.append)
        for f in filelist:
            if f.split()[-1] == directory and f.upper().startswith('D'):
                return True
        return False
    
    def ch_dir_rec(ftp, descending_path_split):
        if len(descending_path_split) == 0:
            return
    
        next_level_directory = descending_path_split.pop(0)
    
        if not directory_exists(ftp,next_level_directory):
            ftp.mkd(next_level_directory)
        ftp.cwd(next_level_directory)
        ch_dir_rec(ftp,descending_path_split)
    

    【讨论】:

      【解决方案4】:

      此代码将在路径中创建所有丢失的文件夹:

      ...
      
      def chdir(ftp_path, ftp_conn):
          dirs = [d for d in ftp_path.split('/') if d != '']
          for p in dirs:
              print(p)
              check_dir(p, ftp_conn)
      
      
      def check_dir(dir, ftp_conn):
          filelist = []
          ftp_conn.retrlines('LIST', filelist.append)
          found = False
      
          for f in filelist:
              if f.split()[-1] == dir and f.lower().startswith('d'):
                  found = True
      
          if not found:
              ftp_conn.mkd(dir)
          ftp_conn.cwd(dir)
      
      if __name__ == '__main__':
          ftp_conn = ... # ftp connection
          t = 'FTP/for_Vadim/1/2/3/'
      
          chdir(t, ftp_conn)
      

      此代码将检查路径中的所有目录并创建缺失的目录

      在“FTP/for_Vadim/”之前 在“FTP/for_Vadim/1/2/3/”之后

      【讨论】:

        【解决方案5】:

        我正在使用这样的东西(没有 cwd):

        # -*- coding:utf-8 -*-
        
        from ftplib import FTP, error_perm
        
        
        def createDirs(ftp, dirpath):
            """
            Create dir with subdirs.
        
            :param ftp:     connected FTP
            :param dirpath: path (like 'test/test1/test2')
        
            :type ftp:      FTP
            :type dirpath:  str
            :rtype:         None
        
            """
        
            dirpath = dirpath.replace('\\', '/')
            tmp = dirpath.split('/')
            dirs = []
        
            for _ in tmp:
                if len(dirs) == 0:
                    dirs.append(_)
                    continue
        
                dirs.append(dirs[-1] + '/' + _)
        
            for _ in dirs:
                try:
                    ftp.mkd(_)
                except error_perm as e:
                    e_str = str(e)
                    if '550' in e_str and 'File exists' in e_str:
                        continue
        
        
        if __name__ == '__main__':
            # init ftp
            createDirs(ftp=ftp, dirpath='test/1/2/3')
        

        【讨论】:

          【解决方案6】:

          我正在使用以下几行来解决 FTP 文件复制缺少的目录路径

          import os
          ftps = FTP_TLS('ftps_server')
          ftps.connect()
          ftps.login()
          
          destination_dir_path = 'some/dir/path'          # directory path on FTP
          dir_path = ''
          for i in destination_dir_path.split('/'):
              dir_path = os.path.join(dir_path,i)
              if i not in ftps.nlst(os.path.dirname(dir_path)):
                  ftps.mkd(dir_path)                      # create directory on the FTP
          ftps.storbinary(...)                            # store file using the binary mode
          

          【讨论】:

            【解决方案7】:

            另一种方法是简单地遍历每个路径元素,创建下一个并更改到新创建的目录。我的用例相当简单,因为我将项目从一个 FTP 服务器复制到另一个。

            def create_ftp_path(session: ftplib.FTP, required_dir: str):
                required_dir = required_dir.split('/')[:-1]
                for path_item in required_dir:
                    if path_item.strip() == '':
                        continue
                    path_item = path_item.replace('/', '')
                    try:
                        session.cwd(path_item)
                    except:
                        session.mkd(path_item)
                        session.cwd(path_item)
            

            注意事项:

            • 此函数假定您已将 FTP 会话的目录更改为某个基本路径,并且 required_dir 是该基本路径的路径。
            • required_dir 包含文件名作为最后一个元素。
            • 我正在删除所有 / 字符,因为在我的情况下它们会导致 553 permission denied 异常。
            • 缺少异常处理,但在我的情况下,上传验证在代码中进一步进行,因此即使失败也会被进一步捕获。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-20
              • 2021-09-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多