在python的标准库ftplib中,FTP类提供了一个dir()函数,可以检索出当前路径下文件列表和这些文件有关的信息并打印出来,但是这个函数并没有返回值,只有打印的功能
FTP类还提供另一个nlst()函数,与dir()函数类似,可以检索出文件名列表并为每一行调用一个回调函数,默认回调函数会将该行打印到sys.stdout,但是这些列表并不包括目录,也没有完整的详细信息
想要获取FTP目录下所有内容并返回,想了半天,还是决定从源码下手
dir()源码:
def dir(self, *args):
'''List a directory in long form.
By default list current directory to stdout.
Optional last argument is callback function; all
non-empty arguments before it are concatenated to the
LIST command. (This *should* only be used for a pathname.)'''
cmd = 'LIST'
func = None
if args[-1:] and type(args[-1]) != type(''):
args, func = args[:-1], args[-1]
for arg in args:
if arg:
cmd = cmd + (' ' + arg)
self.retrlines(cmd, func)
nlst()源码:
def nlst(self, *args):
'''Return a list of files in a given directory (default the current).'''
cmd = 'NLST'
for arg in args:
cmd = cmd + (' ' + arg)
files = []
self.retrlines(cmd, files.append)
return files
不难发现dir()和nlst()都是建立在retrlines()函数的基础之上的
retrlines()源码:
def retrlines(self, cmd, callback = None):
"""Retrieve data in line mode. A new port is created for you.
Args:
cmd: A RETR, LIST, or NLST command.
callback: An optional single parameter callable that is called
for each line with the trailing CRLF stripped.
[default: print_line()]
Returns:
The response code.
"""
if callback is None:
callback = print_line
resp = self.sendcmd('TYPE A')
with self.transfercmd(cmd) as conn, \
conn.makefile('r', encoding=self.encoding) as fp:
while 1:
line = fp.readline(self.maxline + 1)
if len(line) > self.maxline:
raise Error("got more than %d bytes" % self.maxline)
if self.debugging > 2:
print('*retr*', repr(line))
if not line:
break
if line[-2:] == CRLF:
line = line[:-2]
elif line[-1:] == '\n':
line = line[:-1]
callback(line)
# shutdown ssl layer
if _SSLSocket is not None and isinstance(conn, _SSLSocket):
conn.unwrap()
return self.voidresp()
官方对retrlines()函数的解释:
FTP.retrlines(cmd, callback=None)
Retrieve a file or directory listing in ASCII transfer mode. cmd should be an appropriate RETR command (see retrbinary()) or a command such as LIST or NLST (usually just the string 'LIST'). LIST retrieves a list of files and information about those files. NLST retrieves a list of file names. The callback function is called for each line with a string argument containing the line with the trailing CRLF stripped. The default callback prints the line to sys.stdout.
所以博主决定套用nlst()函数来进行修改,内容搞定,该如何判断是文件夹还是文件呢,这时博主发现一篇文章
这篇文章提出了一个思路:用ftplib库提供的cwd()函数向目录下所有内容发出进入目录的请求,用try方法抓取错误信息并进行判断,从而达到判断文件还是文件夹的目的
上代码:
#!/usr/bin/env python
# coding: utf-8
from ftplib import FTP
# ftp主机
host = ''
# 用户名与密码
user = ''
passwd = ''
# ftp登录
class MyFTP(FTP):
# 指定FTP的编码
encoding = 'GBK'
def ftp_login(self):
"""登录"""
try:
self.connect(host=host)
self.login(user=user,passwd=passwd)
except:
print('登录失败,请检查')
# 停止程序
exit()
else:
print('登录成功')
def content(self,*args):
"""返回所有内容的详细信息的list"""
cmd = 'LIST'
for arg in args:
cmd = cmd + (' ' + arg)
files = []
self.retrlines(cmd, files.append)
return files
def file_dirs(self):
"""返回内容的文件名"""
files = []
file_names = self.content()
# print(file_names)
# 循环详细信息,取出文件名
for file_name in file_names:
file_name = file_name.split(' ')[-1]
if file_name != '.' and file_name != '..':
files.append(file_name)
return files
def test():
# 实例化
ftp = MyFTP()
# 登录
ftp.ftp_login()
file_name = ftp.file_dirs()
# print(file_name)
for name in file_name:
try:
ftp.cwd(name)
print(name+'是文件夹')
except:
print(name+'不是文件夹')
else:
# 打开路径没问题,类型是文件夹,返回上一级
ftp.cwd('..')
if __name__ == "__main__":
test()