I'm currently trying to upload a file to a ftp server using Python's ftplib library. The file is relatively small (~400MB), but my script always crashes the same way:
total_size = 492917709
Traceback (most recent call last):
File "ftpmule.py", line 83, in <module>
dest_ftp.storbinary('RETR %s' % base_fn, fhandle, 1024)
File "/usr/lib/python2.6/ftplib.py", line 233, in voidresp
resp = self.getresp()
File "/usr/lib/python2.6/ftplib.py", line 266, in getresp
raise error_temp, resp
ftplib.error_temp: 421 Data timeout. Reconnect. Sorry.
Relevant code:
dest_ftp = FTP(ftp_dest_host)
dest_ftp.login(ftp_user, ftp_pass)
dest_ftp.cwd(ftp_dest_path)
filename = "file.zip"
with open(filename, 'rb') as fhandle:
dest_ftp.storbinary('RETR %s' % filename, fhandle, 1024)
From you comments, the server does not support the passive mode. Python ftplib uses passive mode by default since 2.2, so you have to explicitely disable it with set_pasv(False):
dest_ftp = FTP(ftp_dest_host)
dest_ftp.login(ftp_user, ftp_pass)
dest_ftp.cwd(ftp_dest_path)
dest_ftp.set_pasv(False)
filename = "file.zip"
with open(filename, 'rb') as fhandle:
dest_ftp.storbinary('RETR %s' % filename, fhandle, 1024)
Related
I made an FTP client to transfer files to an FTP server, but it keeps showing me the same errors no matter how I change the storbinary function
from ftplib import FTP
import os
from pathlib import Path
ftp = FTP()
ftp.connect('127.0.0.1', 2121)
ftp.login('user', '12345')
ftp.pwd()
ftp.retrlines('LIST')
ftp.quit()
def uploadfile():
filename = 'C:\\Users\\RE\\Desktop\\Software dev\\Ftp client and server\\test.txt'
localfile = open(filename, 'rb')
ftp.storbinary('STOR %s' %os.path.basename(filename), localfile, 1024)
localfile.close()
uploadfile()
ftp.retrlines('LIST')
fetchfile()
ftp.quit()
This is my error log
Traceback (most recent call last):
File "C:\Users\RE\Desktop\Software dev\Ftp client and server\ftp-client.py", line 24, in <module>
uploadfile()
File "C:\Users\RE\Desktop\Software dev\Ftp client and server\ftp-client.py", line 21, in uploadfile
ftp.storbinary('STOR %s' %os.path.basename(filename), localfile, 1024)
File "C:\Users\RE\AppData\Local\Programs\Python\Python37\lib\ftplib.py", line 503, in storbinary
self.voidcmd('TYPE I')
File "C:\Users\RE\AppData\Local\Programs\Python\Python37\lib\ftplib.py", line 277, in voidcmd
self.putcmd(cmd)
File "C:\Users\RE\AppData\Local\Programs\Python\Python37\lib\ftplib.py", line 199, in putcmd
self.putline(line)
File "C:\Users\RE\AppData\Local\Programs\Python\Python37\lib\ftplib.py", line 194, in putline
self.sock.sendall(line.encode(self.encoding))
AttributeError: 'NoneType' object has no attribute 'sendall'
You are effectively doing this:
ftp.quit()
uploadfile()
So I believe it's quite clear, why the upload fails. You close the session before the upload.
I'm a newb at python, so please excuse the hack job I created in order to transfer the contents of a folder into an ssh server.
The problem is that it works great in my test server, but as soon as run it against the actual server that I need to upload files for I receive the error below, and I'm not sure what it means.
I've googled it, but I can't figure it out, please help.
Thanks.
import paramiko
import glob
import os
from shutil import move
host = "192.168.1.87" #hard-coded
port = 22
password ="passwd" #hard-coded
username = "administator" #hard-coded
remotepath ='' #hard-coded
localpath = 'D:\\PH/PH_PROD\\PowerConnectInterf1_WINS\\bin\\data\\Sheex\\bc\\945\\'
#build filename array
os.chdir("D:/PH/PH_PROD/PowerConnectInterf1_WINS/bin/data/Sheex/bc/945")
filelist=[]
for files in glob.glob( "2016*" ):
f = open(files, 'r')
filelist.append(f.name)
f.close()
if (len(filelist)>0):
transport = paramiko.Transport((host, port))
transport.connect(username=username, password=password)
sftp = paramiko.SFTPClient.from_transport(transport)
for s in filelist:
#print remotepath+s
sftp.put(localpath+s,remotepath+s)
#os.rename(localpath+s,localpath+"945back/"+s)
sftp.close()
transport.close()
#print 'Upload done.'
Error:
D:\Scripts>python mysftp.py
Traceback (most recent call last):
File "mysftp.py", line 37, in <module>
sftp.put(localpath+s,remotepath+s)
File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 676, in put
return self.putfo(fl, remotepath, file_size, callback, confirm)
File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 634, in put
fo
with self.file(remotepath, 'wb') as fr:
File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 327, in ope
n
t, msg = self._request(CMD_OPEN, filename, imode, attrblock)
File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 730, in _re
quest
return self._read_response(num)
File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 781, in _re
ad_response
self._convert_status(msg)
File "C:\Python27\lib\site-packages\paramiko\sftp_client.py", line 807, in _co
nvert_status
raise IOError(errno.ENOENT, text)
IOError: [Errno 2] Invalid file ID
It sounds like the path you are writing on the server doesn't exist. You should check and create if doesn't exist.
I've written a Python script that is part of my attempt to automate daily ftp transfers from my server. I've tested the script with a number of files and file types (html, mp3, png, jpg, etc.) and everything seems to work out fine so far.
However, when I try to download a simple text file, 'file.txt' (9 kb), the download fails, although I account for text files and switch from binary to text mode for the transfer. The following exception is thrown by ftplib:
ftplib.error_perm: 550 file.txt: No such file or directory
Here's my script:
from ftplib import FTP_TLS, error_perm
import os
def open_connection(server, user, pwd, work_dir=None):
global ftps
try:
ftps = FTP_TLS(host=server)
ftps.login(user=user, passwd=pwd)
ftps.prot_p() # switch to secure data connection
if work_dir != None:
ftps.cwd(work_dir)
else:
pass
except:
pass
def download_file(remote_path, local_path):
remote_file = os.path.basename(remote_path)
local_file_path = os.path.join(local_path, remote_file)
# differentiate between text and binary files
file_type, encoding = guess_type_and_encoding(remote_file)
# possibly needs a permission exception catch
if file_type.split("/")[0] == "text" and encoding == None:
# use text mode for transfer
local_file = open(local_file_path, 'w')
def callback(line): local_file.write(line + "\n")
ftps.retrlines("RETR " + remote_file, callback)
local_file.close()
else:
# use binary mode for transfer
local_file = open(local_file_path, 'wb')
ftps.retrbinary("RETR " + remote_file, local_file.write)
local_file.close()
return
def guess_type_and_encoding(filename):
from mimetypes import guess_type, add_type
add_type('text/x-python-win', '.pyw') # not in tables
mimetype, encoding = guess_type(filename, False) # allow extras
mimetype = mimetype or "?/?" # type unknown
return mimetype, encoding
open_connection(server, user, pwd, work_dir)
download_file("/files/dir/file.txt", "/Users/username/Desktop")
ftps.close()
I don't get why the error is raised!? The arguments 'remote_path' and 'local_path' are correctly provided. Both paths exist! 'file.txt' exists on the server under /files/dir and /Users/username/Desktop points to my desktop on OS X.
Here's the detailed ftplib error:
Traceback (most recent call last):
File "ftp2.py", line 138, in <module>
download_file("/files/dir/file.txt", "/Users/username/Desktop")
File "ftp2.py", line 93, in download_file
ftps.retrlines("RETR " + remote_file, callback)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ftplib.py", line 735, in retrlines
conn = self.transfercmd(cmd)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ftplib.py", line 376, in transfercmd
return self.ntransfercmd(cmd, rest)[0]
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ftplib.py", line 710, in ntransfercmd
conn, size = FTP.ntransfercmd(self, cmd, rest)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ftplib.py", line 339, in ntransfercmd
resp = self.sendcmd(cmd)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ftplib.py", line 249, in sendcmd
return self.getresp()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ftplib.py", line 224, in getresp
raise error_perm, resp
ftplib.error_perm: 550 file.txt: No such file or directory
Any help is greatly appreciated.
Thanks. :)
Try to
replace remote_file
in ftps.retrlines("RETR " + remote_file, callback)
with remote_path.
I'm coding a script to check a FTP directory and download the new files. This is part of the code:
from ftplib import FTP
import os
ftp = FTP(ftp_lance)
ftp.login(login, password)
ftp.cwd('xxxxxx')
FTP_list = ftp.nlst()
lista_diferenca = [file for file in FTP_list if file not in local_list]
for file in lista_diferenca:
local_filename = os.path.join(cache, file)
ftp.retrbinary('REST ' + file, open(local_filename, 'wb').write)
When I run it, I get this error message:
Traceback (most recent call last):
File "D:\Scripts\Istari\Radagast\Radagast.py", line 44, in <module>
ftp.retrbinary('REST tabela14_pag5.pdf', open(local_filename, 'wb').write)
File "D:\Portable Python 2.7.6.1\App\lib\ftplib.py", line 414, in retrbinary
conn = self.transfercmd(cmd, rest)
File "D:\Portable Python 2.7.6.1\App\lib\ftplib.py", line 376, in transfercmd
return self.ntransfercmd(cmd, rest)[0]
File "D:\Portable Python 2.7.6.1\App\lib\ftplib.py", line 339, in ntransfercmd
resp = self.sendcmd(cmd)
File "D:\Portable Python 2.7.6.1\App\lib\ftplib.py", line 249, in sendcmd
return self.getresp()
File "D:\Portable Python 2.7.6.1\App\lib\ftplib.py", line 224, in getresp
raise error_perm, resp
error_perm: 501 Bad parameter. Numeric value required
I check several sites searching for this kind of error and find nothing. It seems that my retrbinaty is broken, but the arguments looks right (first the 'Rest' + file, and then the callback function).
Some idea about my error?
You need to specify the FTP command RETR, not REST:
ftp.retrbinary('RETR ' + file, open(local_filename, 'wb').write)
I have been trying to script a code with python to grade the main directory of that ftp and archive it into a the local pc. I am not an amateur coder and python is fairly new to me.
What I am getting as an error right now is.
File "C:\Users\Ali\Desktop\ftp_archiving_script.py", line 24, in <module>
ftpDownload = ftp.retrbinary('RETR', filename)
Code:
from ftplib import FTP
import zipfile
import os
try:
import zlib
compression = zipfile.ZIP_DEFLATED
except:
compression = zipfile.ZIP_STORED
modes = { zipfile.ZIP_DEFLATED: "deflated",
zipfile.ZIP_STORED: "stored",
}
#print "Logging in..."
with FTP('xxx.xxx.xxx') as ftp: #hostname goes here
ftp.login('xxxx','xxxx') #user followed by pass
#print "changing to root directory"
ftp.mlsd('//')
#print "Accessing files"
filenames = []
#print filenames
ftp.retrlines('NLST', filenames.append)
try:
for filename in filenames:
ftpDownload = ftp.retrbinary('RETR', filename)
with ZipFile(os.path.join('C:\\','DC_archive.zip'), 'w') as myzip:
myzip.write(ftpDownload, compress_type=compression)
myzip.close()
finally:
#print "closing"
ftp.close()
ftp.quit()
Can anyone enlighten me on this problem.
Thank you,
Update
try:
for filename in filenames:
with io.StringIO() as fObject:
ftp.retrbinary('RETR %s' %filename, fObject.write)
with ZipFile(os.path.join('C:\\','DC_archive.zip'), 'w') as myzip:
myzip.write(fObject, compress_type=compression)
myzip.close()
updated Traceback for #fals... Also this is using your code below and not the one I have at the top.
Traceback (most recent call last):
File "C:\Users\Ali\Desktop\ftp_archive2.py", line 20, in <module>
ftpDownload = ftp.retrbinary('RETR ' + filename, f.write)
File "C:\Python33\lib\ftplib.py", line 424, in retrbinary
with self.transfercmd(cmd, rest) as conn:
File "C:\Python33\lib\ftplib.py", line 386, in transfercmd
return self.ntransfercmd(cmd, rest)[0]
File "C:\Python33\lib\ftplib.py", line 352, in ntransfercmd
resp = self.sendcmd(cmd)
File "C:\Python33\lib\ftplib.py", line 259, in sendcmd
return self.getresp()
File "C:\Python33\lib\ftplib.py", line 233, in getresp
raise error_perm(resp)
ftplib.error_perm: 550 File not found
From the Python documentation for ftplib.retrbinary:
FTP.retrbinary(command, callback[, maxblocksize[, rest]])
Retrieve a file in binary transfer mode. command should be an
appropriate RETR command: 'RETR filename'. The callback function is
called for each block of data received, with a single string argument
giving the data block.
Nowhere does it indicate that it returns a file-like object or string.
Instead, you have to create your own callback to write to a file object.
with open('my-downloaded-file', 'wb') as f:
ftp.retrbinary('RETR %s' % filename, f.write)
Here, f.write is the callback which will receive data as it arrives from the socket. If you don't want to save the file to disk using open, you can use the StringIO module to simulate a file in memory.
Try following code:
import ftplib
from io import BytesIO
import os
import zipfile
REMOTE_HOST = 'xxx.xxx.xxx'
REMOTE_USER = '...'
REMOTE_PASS = '...'
REMOTE_DIR_PATH = '//'
LOCAL_ZIP_PATH = os.path.join(os.path.expanduser('~'), 'Desktop', 'DC_archive.zip')
ftp = ftplib.FTP(REMOTE_HOST)
try:
ftp.login(REMOTE_USER, REMOTE_PASS)
ftp.cwd(REMOTE_DIR_PATH)
filenames = ftp.nlst()
with zipfile.ZipFile(LOCAL_ZIP_PATH, 'w') as zf:
for filename in filenames:
with BytesIO() as f:
try:
ftpDownload = ftp.retrbinary('RETR ' + filename, f.write)
zf.writestr(filename, f.getvalue())
except ftplib.Error as e:
print('Skip {}: {}'.format(filename, e))
finally:
ftp.quit()