简体   繁体   English

尝试使用 FTP_TLS 从同一目录下载第二个文件时出现“ftplib.error_perm: 550 Operation not allowed”

[英]"ftplib.error_perm: 550 Operation not permitted" when trying to download the second file from the same directory using FTP_TLS

Got this error while running my script: ftplib.error_perm: 550 Operation not permitted运行我的脚本时出现此错误: ftplib.error_perm: 550 Operation not permitted

ftpdownloader.py: ftpdownloader.py:

import ftplib
import threading
import logging
import os


class Client:
    def __init__(self, host, port, username, passwd):
        self.host = host
        self.port = port
        self.username = username
        self.passwd = passwd
        self.ftp = None
        self.set_ftp()
        self.login_to_ftp()

    def set_ftp(self):
        self.ftp = ftplib.FTP_TLS(self.host)
        self.ftp.set_debuglevel(True)
        self.ftp.set_pasv(True)

    def login_to_ftp(self):
        self.ftp.login(self.username, self.passwd)
        self.ftp.prot_p()

    def download_file(self, filename, local_filename=None):
        logging.info('Will download this file : "%s"', filename)
        if local_filename is None:
            local_filename = filename
        self.ftp.voidcmd('TYPE I')
        sock = self.ftp.transfercmd('RETR ' + filename)

        def background():
            with open(local_filename, 'wb') as f:
                while True:
                    block = sock.recv(1024 * 1024)
                    if not block:
                        break
                    f.write(block)
                logging.debug('will close sock ...')
                sock.close()

        t = threading.Thread(target=background)
        t.start()
        while t.is_alive():
            t.join(20)
            self.ftp.voidcmd('NOOP')
        # self.ftp.close()
        logging.info("File downloaded with success : %s", local_filename)

    def get_directories_list(self, directory_path):
        logging.debug('Getting directories of directory : %s', directory_path)
        directories_list = []
        for elem in self.ftp.mlsd(directory_path):
            if elem[1]['type'] == 'dir':
                directories_list += [elem[0]]
        return directories_list

    def get_files_list(self, directory_path):
        logging.debug('Getting files of directory : %s', directory_path)
        files_list = []
        for elem in self.ftp.mlsd(directory_path):
            if elem[1]['type'] == 'file':
                files_list += [elem[0]]
        return files_list

    def get_all_files_of_directory(self, ftp_directory_root, ftp_directory_path, output_directory_path):
        current_position = ftp_directory_root + ftp_directory_path
        current_output_directory = output_directory_path + ftp_directory_path
        # self.set_ftp()
        # self.login_to_ftp()
        files_list = self.get_files_list(current_position)
        directories_list = self.get_directories_list(current_position)

        os.makedirs(current_output_directory, exist_ok=True)

        for file in files_list:
            self.download_file(current_position + '/' + file, current_output_directory + '/' + file)
            # self.set_ftp()
            # self.login_to_ftp()

        for directory in directories_list:
            if ftp_directory_path == '/':
                ftp_directory_path = ''
            self.get_all_files_of_directory(ftp_directory_root, ftp_directory_path + '/' + directory,
                                            output_directory_path)

Test script:测试脚本:

test.py:测试.py:

from ftpdownloader import Client

ftp_host_name = 'ftp-hostname'
ftp_port = 21
ftp_username = 'username'
ftp_password = '*******'

client = Client(ftp_host_name, ftp_port, ftp_username, ftp_password)
client.get_all_files_of_directory('/directory1', '/', 'downloads/test')

FTP content: FTP 内容:

 - directory1:
   - directory11:
     - file111.xml
     - file112.zip
   - directory12:
     - file121.xml
     - file122.zip

When I run my test.py script (with commented lines on ftpdownloader.py), the script:当我运行我的 test.py 脚本(在 ftpdownloader.py 上带有注释行)时,脚本:

  • Got the list of directories and files得到目录和文件的列表
  • Download the first founded file (file111.xml)下载第一个创建的文件(file111.xml)
  • ERROR when trying to download the second file (file112.zip)-> ftplib.error_perm: 550 Operation not permitted尝试下载第二个文件 (file112.zip)-> ftplib.error_perm ftplib.error_perm: 550 Operation not permitted

FTP_TLS debug logs: FTP_TLS 调试日志:

*cmd* 'TYPE A'
*resp* '200 Type set to A'
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (81,252,220,78,234,106).'
*cmd* 'MLSD /directory1'
*resp* '150 Opening ASCII mode data connection for MLSD'
*resp* '226 Transfer complete'
*cmd* 'TYPE A'
*resp* '200 Type set to A'
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (81,252,220,78,234,187).'
*cmd* 'MLSD /directory1'
*resp* '150 Opening ASCII mode data connection for MLSD'
*resp* '226 Transfer complete'
*cmd* 'TYPE A'
*resp* '200 Type set to A'
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (81,252,220,78,234,99).'
*cmd* 'MLSD /directory1/directory11'
*resp* '150 Opening ASCII mode data connection for MLSD'
*resp* '226 Transfer complete'
*cmd* 'TYPE A'
*resp* '200 Type set to A'
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (81,252,220,78,234,131).'
*cmd* 'MLSD /directory1/directory11'
*resp* '150 Opening ASCII mode data connection for MLSD'
*resp* '226 Transfer complete'
*cmd* 'TYPE I'
*resp* '200 Type set to I'
*cmd* 'PASV'
*resp* '227 Entering Passive Mode (81,252,220,78,234,126).'
*cmd* 'RETR /directory1/directory11/file111.xml'
*resp* '150 Opening BINARY mode data connection for /directory1/directory11/file111.xml (879 bytes)'
*cmd* 'NOOP'
*resp* '226 Transfer complete'
*cmd* 'TYPE I'
*resp* '550 Operation not permitted'

Traceback (most recent call last):
  File "..../envs/back/lib/python3.9/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 11, in <module>
  File "..../back/tools/ftpdownload.py", line 86, in get_all_files_of_directory
    self.get_all_files_of_directory(ftp_directory_root, ftp_directory_path + '/' + directory,
  File "..../back/tools/ftpdownload.py", line 86, in get_all_files_of_directory
    self.get_all_files_of_directory(ftp_directory_root, ftp_directory_path + '/' + directory,
  File "..../back/tools/ftpdownload.py", line 79, in get_all_files_of_directory
    self.download_file(current_position + '/' + file, current_output_directory + '/' + file)
  File "..../back/tools/ftpdownload.py", line 30, in download_file
    self.ftp.voidcmd('TYPE I')
  File ".../envs/back/lib/python3.9/ftplib.py", line 286, in voidcmd
    return self.voidresp()
  File "..../envs/back/lib/python3.9/ftplib.py", line 259, in voidresp
    resp = self.getresp()
  File "..../envs/back/lib/python3.9/ftplib.py", line 254, in getresp
    raise error_perm(resp)
ftplib.error_perm: 550 Operation not permitted

So, I tried to run the script using login after downloading each file (uncomment lines for ftpdownloader.py script)!因此,我尝试在下载每个文件后使用 login 运行脚本(取消 ftpdownloader.py 脚本的注释行)! It's work but It's too slow comparing FileZilla or other FTP client!它可以工作,但比较 FileZilla 或其他 FTP 客户端太慢了!

Can you help please?你能帮忙吗?

There are at least two problems imo: imo至少有两个问题:

  • You are not reading a response to RETR .您没有阅读对RETR的回复。
  • You are not reading the responses in the order of the requests, so you misinterpret the responses.您没有按照请求的顺序阅读响应,因此您误解了响应。 Consequently, you have many wrong assumptions which make it hard to understand the root cause.因此,您有许多错误的假设,难以理解根本原因。

I believe this is what is happening:我相信这是正在发生的事情:

  1. You send RETR and start the transfer.您发送RETR并开始传输。
  2. You send NOOP and wait for a response.您发送NOOP并等待响应。
  3. But the server (correctly) responds to the requests in the order they are received.但是服务器(正确地)按照收到请求的顺序响应请求。 So it cannot respond NOOP , until RETR completes.所以它不能响应NOOP ,直到RETR完成。
  4. When the transfer finishes, the servers responds with 226 to the RETR .传输完成后,服务器以226响应RETR
  5. Your code misinterprets the 226 as a response to NOOP您的代码将226误解为对NOOP的响应
  6. The server probably sends 550 as a response to NOOP (but that's just a guess)服务器可能会发送550作为对NOOP的响应(但这只是猜测)
  7. Your code fails to read response to RETR (If it did, you will notice the mismatch between responses and answers at the first file already)您的代码无法读取对RETR的响应(如果确实如此,您会注意到第一个文件中的响应和答案之间的不匹配)
  8. You send TYPE command for the second file您为第二个文件发送TYPE命令
  9. You read queued response 550 to RETR and misinterpret it as a response to TYPE .您阅读了对RETR的排队响应550并将其误解为对TYPE的响应。

I do not think the answer you have based your code on is correct.我不认为您基于代码的答案是正确的。 It indeed cannot handle more than one file, as it breaks pairing of requests and responses.它确实不能处理多个文件,因为它破坏了请求和响应的配对。 If you believe the NOOP solves the freeze, then the correct solution might be to just send the NOOP command without waiting for a response using FTP.sendcmd :如果您认为NOOP解决了冻结问题,那么正确的解决方案可能是使用FTP.sendcmd发送NOOP命令而不等待响应:

ftp.sendcmd('NOOP')
noops_sent += 1

And then at the end of the the transfer, you have to wait for the RETR response using FTP.voidresp (see the code of FTP.retrbinary ) and then wait for responses of all queued NOOP commands:然后在传输结束时,您必须使用FTP.voidresp等待RETR响应(参见 FTP.retrbinary 的FTP.retrbinary ),然后等待所有排队的NOOP命令的响应:

ftp.voidresp()
for _ in range(noops_sent):
    ftp.voidresp()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ftplib.error_perm:尝试更改目录时出现 550 - ftplib.error_perm: 550 when trying to change directory ftplib.error_perm:500不知道从ftp下载文件 - ftplib.error_perm: 500 not understood downloading file from ftp ftplib.error_perm:550请求的操作未采取 - ftplib.error_perm: 550 Requested action not taken 如何避免获取 ftplib.error_perm: 550 该进程无法访问该文件,因为它正被另一个进程使用? - How to avoid getting ftplib.error_perm: 550 The process cannot access the file because it is being used by another process? 尝试使用Python FTP_TLS对象下载文件时获取AttributeError? - When trying to download files using a Python FTP_TLS object getting AttributeError? ftplib.error_perm:550将文件作为匿名用户存储时没有足够的权限 - ftplib.error_perm: 550 Not enough privileges while STORing files as anonymous user Python 模块 ftplib FTP_TLS - 错误 530 - Python module ftplib FTP_TLS - Error 530 ftplib.error_perm:553无法创建文件。 (Python 2.4.4) - ftplib.error_perm: 553 Could not create file. (Python 2.4.4) 尝试使用 python ftplib 从 NCBI ftp 下载一系列档案,但 ftplib 在长文件传输结束时冻结 - Trying to download a series of archives from NCBI ftp using python ftplib but ftplib freezes at end of long file transfer python ftplib.error_perm:不支持500协议 - python ftplib.error_perm: 500 Protocol not supported
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM