即使没有错误,Sftp paramiko 和 sshd-mina 也无法在远程服务器上写入。在本地 sftp 服务器上它可以工作

问题描述 投票:0回答:1

我只是展示用于尝试在 sftp 中上传文件的代码:

# Check file size
def check_file_size(path):
    try:
        size = os.path.getsize(path)
        print(f"Local file size: {size} bytes")
        return size
    except OSError as e:
        print(f"Failed to get size of {path}: {e}")
        return None

# Create an SFTP session
def create_sftp_session(hostname, port, username, password):
    transport = paramiko.Transport((hostname, port))
    transport.connect(username=username, password=password)
    sftp = paramiko.SFTPClient.from_transport(transport)
    return sftp, transport

# Upload a file to the remote server, overwriting if it exists
def upload_file(sftp, local_path, remote_path, retries=3):
        try:
            # Create a temporary file and copy content to it
            with tempfile.NamedTemporaryFile(delete=False) as temp_file:
                with open(local_path, 'r') as file:
                    temp_file.write(file.read().encode())
                temp_file_path = temp_file.name
            
            local_size = os.path.getsize(temp_file_path)
            sftp.put(temp_file_path, remote_path)
            remote_size = sftp.stat(remote_path).st_size
            print(f"Remote file size after upload: {remote_size} bytes")
            if local_size != remote_size:
                print(f"Warning: Size mismatch after upload!")
            
            # Clean up temporary file
            os.remove(temp_file_path)
        except IOError as e:
            print(f"Failed to upload {local_path} to {remote_path}: {e}")

# Delete the local file
def delete_local_file(path):
    try:
        os.remove(path)
        print(f"Local file {path} deleted.")
    except OSError as e:
        print(f"Failed to delete {path}: {e}")

# Main execution
def main():
    # Create the local file
    create_local_file(local_file_path)

    # Set up SFTP session and upload file
    sftp, transport = create_sftp_session(hostname, port, username, password)
    try:
        # Upload and overwrite the file
        upload_file(sftp, local_file_path, remote_file_path)
    finally:
        sftp.close()
        transport.close()

    # Delete the local file
    delete_local_file(local_file_path)

if __name__ == "__main__":
    main()

如果针对远程服务器运行它会失败:

无法将 localfile.txt 上传到 /dir/removefile.csv:放入的大小不匹配! 94!= 141

我使用 docker 对本地 sftp 服务器运行相同的代码,它可以工作。使用 sshd-mina 的代码也是如此(此处未显示)。这是意料之外的事。为什么它对远程服务器不起作用?

我注意到的另一件事是,如果我将 upload_file 函数更改为:

# Upload a file to the remote server, overwriting if it exists
def upload_file(sftp, local_path, remote_path, retries=3):
    for attempt in range(retries):
        try:
            # Create a temporary file and copy content to it
            with tempfile.NamedTemporaryFile(delete=False) as temp_file:
                with open(local_path, 'r') as file:
                    temp_file.write(file.read().encode())
                temp_file_path = temp_file.name
            
            local_size = os.path.getsize(temp_file_path)
            sftp.put(temp_file_path, remote_path)
            remote_size = sftp.stat(remote_path).st_size
            print(f"Remote file size after upload: {remote_size} bytes")
            if local_size != remote_size:
                print(f"Warning: Size mismatch after upload!")
            
            # Clean up temporary file
            os.remove(temp_file_path)
            break  # Exit loop if upload is successful
        except IOError as e:
            print(f"Attempt {attempt + 1} failed to upload {local_path} to {remote_path}: {e}")
            if attempt < retries - 1:
                print("Retrying...")
                time.sleep(5)  # Wait before retrying

第二次尝试就成功了! (更改在于仅在引发异常时重试)。

使用内容创建的本地文件 localfile.txt。尝试1失败 将 localfile.txt 上传到 /flex-selections/Portfolio.csv:大小不匹配 输入! 94 != 141 正在重试...上传后远程文件大小: 141 bytes 本地文件 localfile.txt 已删除。

这怎么可能?

sftp paramiko
1个回答
0
投票

问题出在服务器端。使用的旧版 S/FTP 前门并不完全支持所有 SFTP 命令/功能(它是具有 SFTP 增强功能的 FTP 服务器。)。

S/FTP 前门无法正确处理“put”方法中的目标目录,并且不会将“CWD”命令转发到 FTP 服务器。

解决方法:在“put()”之前添加“chdir()”或“listdir()”会强制执行“CWD”并解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.