我正在使用此脚本连接到示例 ftp 服务器并列出可用目录:
from ftplib import FTP
ftp = FTP('ftp.cwi.nl') # connect to host, default port (some example server, i'll use other one)
ftp.login() # user anonymous, passwd anonymous@
ftp.retrlines('LIST') # list directory contents
ftp.quit()
如何使用 ftp.retrlines('LIST') 输出来检查目录(例如 public_html)是否存在,如果存在 cd 到它,然后执行一些其他代码并退出;如果不立即执行代码并退出?
Nslt 将列出 ftp 服务器中所有文件的数组。只需检查您的文件夹名称是否在那里。
from ftplib import FTP
ftp = FTP('yourserver')
ftp.login('username', 'password')
folderName = 'yourFolderName'
if folderName in ftp.nlst():
#do needed task
您可以使用列表。例子
import ftplib
server="localhost"
user="user"
password="[email protected]"
try:
ftp = ftplib.FTP(server)
ftp.login(user,password)
except Exception,e:
print e
else:
filelist = [] #to store all files
ftp.retrlines('LIST',filelist.append) # append to list
f=0
for f in filelist:
if "public_html" in f:
#do something
f=1
if f==0:
print "No public_html"
#do your processing here
您可以通过控制连接发送“MLST 路径”。 这将返回包含路径的 type 的行(注意此处的“type=dir”):
250-Listing "/home/user":
modify=20131113091701;perm=el;size=4096;type=dir;unique=813gc0004; /
250 End MLST.
翻译成Python应该是这样的:
import ftplib
ftp = ftplib.FTP()
ftp.connect('ftp.somedomain.com', 21)
ftp.login()
resp = ftp.sendcmd('MLST pathname')
if 'type=dir;' in resp:
# it should be a directory
pass
当然,上面的代码并不是 100% 可靠,需要一个“真正的”解析器。 您可以在 ftplib.py 中查看 MLSD 命令的实现,它非常相似(MLSD 与 MLST 的不同之处在于,通过 data 连接发送响应,但传输的行的格式是相同的): http://hg.python.org/cpython/file/8af2dc11464f/Lib/ftplib.py#l577
ghostdog74 的答案附带的示例有一点错误:您返回的列表是响应的整行,因此您会得到类似的内容
drwxrwxrwx 4 5063 5063 4096 Sep 13 20:00 resized
这意味着如果您的目录名称类似于“50”(在我的例子中就是这样),您将得到误报。我修改了代码来处理这个问题:
def directory_exists_here(self, directory_name):
filelist = []
self.ftp.retrlines('LIST',filelist.append)
for f in filelist:
if f.split()[-1] == directory_name:
return True
return False
注意,这是我编写的 FTP 包装类内部,self.ftp 是实际的 FTP 连接。
汤姆是对的,但没有人投票支持他 然而,为了让投票给 Ghostdog74 的人满意,我将混合并编写这段代码,对我有用,也应该对你们有用。
import ftplib
server="localhost"
user="user"
uploadToDir="public_html"
password="[email protected]"
try:
ftp = ftplib.FTP(server)
ftp.login(user,password)
except Exception,e:
print e
else:
filelist = [] #to store all files
ftp.retrlines('NLST',filelist.append) # append to list
num=0
for f in filelist:
if f.split()[-1] == uploadToDir:
#do something
num=1
if num==0:
print "No public_html"
#do your processing here
首先,如果你遵循 Ghost Dog 方法,即使你在 f 中说目录“public”,即使它不存在,它也会评估为 true,因为单词 public 存在于“public_html”中,所以这就是 Tom if 条件可以使用的地方 所以我将其更改为 if f.split()[-1] == uploadToDir:.
另外,如果你输入一个不存在的目录名,但存在一些文件和文件夹,则 Ghostdog74 的第二个文件和文件夹将永远不会执行,因为它永远不会为 0,因为在 for 循环中被 f 覆盖,所以我使用 num 变量而不是 f ,瞧善良随之而来......
Vinay 和 Jonathon 的评论是正确的。
在 3.x 中,
nlst()
方法已弃用。使用此代码:
import ftplib
remote = ftplib.FTP('example.com')
remote.login()
if 'foo' in [name for name, data in list(remote.mlsd())]:
# do your stuff
需要
list()
调用,因为 mlsd()
返回一个生成器,并且它们不支持检查其中的内容(没有 __contains__()
方法)。
您可以将
[name for name, data in list(remote.mlsd())]
list comp 包装在方法的函数中,并在您需要检查目录(或文件)是否存在时调用它。
=> 我在谷歌搜索一种使用 python 中的 ftplib 检查文件是否存在的方法时发现了这个网页。以下是我的想法(希望对某人有帮助):
=> 当尝试列出不存在的文件/目录时,ftplib 会引发异常。尽管添加 try/ except 块是一种标准做法并且是一个好主意,但我希望我的 FTP 脚本仅在确保文件存在后才下载文件。这有助于使我的脚本更简单 - 至少在可以列出 FTP 服务器上的目录时是这样。
例如,Edgar FTP 服务器有多个文件存储在目录 /edgar/daily-index/ 下。每个文件的名称类似于“master.YYYYMMDD.idx”。不保证每个日期 (YYYYMMDD) 都存在文件 - 没有日期为 2013 年 11 月 24 日的文件,但有一个日期为:2013 年 11 月 22 日的文件。在这两种情况下列表如何工作?
# Code
from __future__ import print_function
import ftplib
ftp_client = ftplib.FTP("ftp.sec.gov", "anonymous", "[email protected]")
resp = ftp_client.sendcmd("MLST /edgar/daily-index/master.20131122.idx")
print(resp)
resp = ftp_client.sendcmd("MLST /edgar/daily-index/master.20131124.idx")
print(resp)
# Output
250-Start of list for /edgar/daily-index/master.20131122.idx
modify=20131123030124;perm=adfr;size=301580;type=file;unique=11UAEAA398;
UNIX.group=1;UNIX.mode=0644;UNIX.owner=1019;
/edgar/daily-index/master.20131122.idx
250 End of list
Traceback (most recent call last):
File "", line 10, in <module>
resp = ftp_client.sendcmd("MLST /edgar/daily-index/master.20131124.idx")
File "lib/python2.7/ftplib.py", line 244, in sendcmd
return self.getresp()
File "lib/python2.7/ftplib.py", line 219, in getresp
raise error_perm, resp
ftplib.error_perm: 550 '/edgar/daily-index/master.20131124.idx' cannot be listed
正如预期的那样,列出不存在的文件会生成异常。
=> 因为我知道 Edgar FTP 服务器肯定会有目录 /edgar/daily-index/,所以我的脚本可以执行以下操作以避免由于不存在的文件而引发异常:
a) 列出该目录。
b) 下载所需文件(如果此列表中存在) - 为了检查列表,我通常在列表操作返回的字符串列表上执行正则表达式搜索。
例如,此脚本尝试下载过去三天的文件。如果找到特定日期的文件,则下载该文件,否则什么也不会发生。
import ftplib
import re
from datetime import date, timedelta
ftp_client = ftplib.FTP("ftp.sec.gov", "anonymous", "[email protected]")
listing = []
# List the directory and store each directory entry as a string in an array
ftp_client.retrlines("LIST /edgar/daily-index", listing.append)
# go back 1,2 and 3 days
for diff in [1,2,3]:
today = (date.today() - timedelta(days=diff)).strftime("%Y%m%d")
month = (date.today() - timedelta(days=diff)).strftime("%Y_%m")
# the absolute path of the file we want to download - if it indeed exists
file_path = "/edgar/daily-index/master.%(date)s.idx" % { "date": today }
# create a regex to match the file's name
pattern = re.compile("master.%(date)s.idx" % { "date": today })
# filter out elements from the listing that match the pattern
found = filter(lambda x: re.search(pattern, x) != None, listing)
if( len(found) > 0 ):
ftp_client.retrbinary(
"RETR %(file_path)s" % { "file_path": file_path },
open(
'./edgar/daily-index/%(month)s/master.%(date)s.idx' % {
"date": today
}, 'wb'
).write
)
=> 有趣的是,在某些情况下我们无法列出 FTP 服务器上的目录。例如,edgar FTP 服务器不允许在 /edgar/data 上列出,因为它包含太多子目录。在这种情况下,我将无法使用此处描述的“列出并检查是否存在”方法 - 在这些情况下,我必须在下载器脚本中使用异常处理来从不存在的文件/目录访问尝试中恢复。
from ftplib import FTP
ftp = FTP()
ftp.connect(hostname, 21)
ftp.login(username,password)
try:
ftp.cwd('your folder name')
#do the code for successfull cd
except Exception:
#do the code for folder not exists
这是我用于同一问题/查询的方法:
# imports (made more general)
import ftplib
# Login information (genericized)
ftp = FTP(hostname)
ftp.login(username, password)
# added function for purpose
def ftp_dir_contains_folder(dir, folder_name) -> bool:
"""Check ftp directory for specific directory by name (full matches only)."""
# get contents of directory with "Facts"
dir_contents = ftp.mlsd(dir)
# Look for match - directory type and full match of name
for name, args in dir_contents:
if name == folder_name and args["type"] == "dir":
return True
return False
# Arbitrary example using current working directory with "public_html" as the full dir name
public_html_folder_exists = ftp_dir_contains_folder(ftp.pwd(), "public_html")
# with some arbitrary follow-up actions (requested by OP)
if public_html_folder_exists:
# do something - Change dir to it
ftp.cwd("/public_html")
# Insert some special action
else:
# Arbitrary other action
ftp.mkd("/public_html")
# ...