Checking if object on FTP server is file or directory using Python and ftplib
There's no better way (with FTP protocol in general, not just with ftplib).
The MLST
/MLSD
is the only correct and reliable way.
If you cannot use MLST
/MLSD
, trying CWD
is the next best option.
Trying to parse LIST
is a fallback option. But you need to know that the server uses listing format your program understands.
Determine if a listing is a directory or file in Python over FTP
Unfortunately FTP doesn't have a command to list just folders so parsing the results you get from ftp.dir() would be 'best'.
A simple app assuming a standard result from ls (not a windows ftp)
from ftplib import FTP
ftp = FTP(host, user, passwd)
for r in ftp.dir():
if r.upper().startswith('D'):
print r[58:] # Starting point
Standard FTP Commands
Custom FTP Commands
Using Python's ftplib to get a directory listing, portably
Try using ftp.nlst(dir)
.
However, note that if the folder is empty, it might throw an error:
files = []
try:
files = ftp.nlst()
except ftplib.error_perm as resp:
if str(resp) == "550 No files found":
print "No files in this directory"
else:
raise
for f in files:
print f
Get the latest FTP folder name in Python
If your FTP server supports MLSD
command, a solution is easy:
If you want to base the decision on a modification timestamp:
entries = list(ftp.mlsd())
# Only interested in directories
entries = [entry for entry in entries if entry[1]["type"] == "dir"]
# Sort by timestamp
entries.sort(key = lambda entry: entry[1]['modify'], reverse = True)
# Pick the first one
latest_name = entries[0][0]
print(latest_name)If you want to use a file name:
# Sort by filename
entries.sort(key = lambda entry: entry[0], reverse = True)
If you need to rely on an obsolete LIST
command, you have to parse a proprietary listing it returns.
A common *nix listing is like:
drw-r--r-- 1 user group 4096 Mar 26 2018 folder1-20180326
drw-r--r-- 1 user group 4096 Jun 18 11:21 folder2-20180618
-rw-r--r-- 1 user group 4467 Mar 27 2018 file-20180327.zip
-rw-r--r-- 1 user group 124529 Jun 18 15:31 file-20180618.zip
With a listing like this, this code will do:
If you want to base the decision on a modification timestamp:
lines = []
ftp.dir("", lines.append)
latest_time = None
latest_name = None
for line in lines:
tokens = line.split(maxsplit = 9)
# Only interested in directories
if tokens[0][0] == "d":
time_str = tokens[5] + " " + tokens[6] + " " + tokens[7]
time = parser.parse(time_str)
if (latest_time is None) or (time > latest_time):
latest_name = tokens[8]
latest_time = time
print(latest_name)If you want to use a file name:
lines = []
ftp.dir("", lines.append)
latest_name = None
for line in lines:
tokens = line.split(maxsplit = 9)
# Only interested in directories
if tokens[0][0] == "d":
name = tokens[8]
if (latest_name is None) or (name > latest_name):
latest_name = name
print(latest_name)
Some FTP servers may return .
and ..
entries in LIST
results. You may need to filter those.
Partially based on: Python FTP get the most recent file by date.
If the folder does not contain any files, only subfolders, there are other easier options.
If you want to base the decision on a modification timestamp and the server supports non-standard
-t
switch, you can use:lines = ftp.nlst("-t")
latest_name = lines[-1]See How to get files in FTP folder sorted by modification time
If you want to use a file name:
lines = ftp.nlst()
latest_name = max(lines)
What is the way to know how any file is updated in ftp location using Python?
You can use the dir
method to get the last modified timestamps from the file listing, and parse the 6th to 8th fields on your own. Note that the 8th field can be either a year or a time of the day, in which case the year is the current year. But then again you don't necessarily have to parse the date/time at all since all you need is to detect change.
>>> from ftplib import FTP
>>> ftp = FTP('ftp.redhat.com')
>>> ftp.login()
'230 Login successful.'
>>> ftp.dir()
lrwxrwxrwx 1 ftp ftp 1 Dec 19 2009 pub -> .
drwxr-xr-x 45 ftp ftp 4096 Jul 05 16:46 redhat
>>> l=[]
>>> ftp.dir(lambda x: l.append(x))
>>> l
['lrwxrwxrwx 1 ftp ftp 1 Dec 19 2009 pub -> .', 'drwxr-xr-x 45 ftp ftp 4096 Jul 05 16:46 redhat']
>>>
Knowing whether or not FTP is still connected with ftplib
You could try retrieving something from the server, and catching any exceptions and returning whether or not it's connected based on that.
For example:
def is_connected(ftp_conn):
try:
ftp_conn.retrlines('LIST')
except (socket.timeout, OSError):
return False
return True
This simple example will print the 'LIST' results to stdout, you can change that by putting your own callback into the retrlines method
(Make sure you set a timeout in the initial FTP object construction, as the default is for it to be None.)
ftp = ftplib.FTP("ftp.gnu.org", timeout=5, user='anonymous', passwd='')
Determine if a ftp file is a regular file or folder with python ftp lib
I don't find any differences between platforms. On which platforms does this not work?:
isFile = lambda e: e[0][0] != 'd'
for e in ftp.dir('.'):
if isFile(e):
foo(e)
else:
bar(e)
Is Django and ftplib connection posible?
Here is a manual that you should check first
Here is a same question that you should check second
Here is an example of correct code:
from ftplib import FTP
with FTP(
conf_settings.FTP_DOMAIN,
conf_settings.FTP_USER,
conf_settings.FTP_PASSWORD
) as ftp:
with open(os.path.join(folder, filename), 'rb') as file:
ftp.storbinary(f'STOR {filename}', file)
Related Topics
Web Scraping Dynamic Content with Python
How to Remove Leading Whitespace in Python
How to Get Char from String by Index
How to Run Python Script on Terminal
How to Print a List with Integers Without the Brackets, Commas and No Quotes
Python Parse Comma-Separated Number into Int
From ... Import or Import ... as for Modules
Best Way to Parse a Url Query String
How to Use a String as a Keyword Argument
Python Float to Int Conversion
List of All Available Matplotlib Backends
Nameerror: Name 'Datetime' Is Not Defined
Iterate Over Individual Bytes in Python 3
Ioerror: [Errno 22] Invalid Mode ('R') or Filename: 'C:\\Python27\Test.Txt'