17

如何检查远程 ftp 上的文件是否是文件夹或不使用 ftplib?

我现在最好的方法是做一个 nlst,并遍历每个文件的调用大小,如果文件出错,那么它是一个文件夹?

有没有更好的办法?我无法解析列表的输出,因为大约有十几个不同的 ftp 服务器(许多非常旧。)

我应该怎么办?

4

15 回答 15

9

ftplib 中没有“isdir”和“isfile”定义。如果您不必使用 ftplib,我建议您使用ftputil

首先你必须安装 ftputil 包。要实现这一点,请使用以下命令:python -m pip install ftputil. 安装后,您可以将库导入到您的代码中。我认为这已经足够解释了。所以,让我们去实现:

import ftputil
with ftputil.FTPHost("host", "username", "password") as ftp_host:
    ftp_host.chdir("/directory/")   
    list = ftp_host.listdir(ftp_host.curdir)
    for fname in list:
        if ftp_host.path.isdir(fname):
            print(fname + " is a directory")
        else:
            print(fname + " is not a directory")
于 2016-10-11T15:01:01.133 回答
7

FTP 是一个非常基本的协议,并且没有内置的协议查询允许您获取每个节点的类型(文件、目录),因此像您找到的启发式方法是唯一的解决方案。

如果获取每个节点的大小不起作用,也许你应该考虑调用FTP.nlst()每个节点:那些出错的将是文件而不是目录。

于 2009-12-31T14:28:08.573 回答
4

您可以使用 MLST 命令:

import ftplib
f = ftplib.FTP()
f.connect("localhost")
f.login()
print f.sendcmd('MLST /')

针对pyftpdlib 服务器,上面的代码打印:

250-Listing "/":
 modify=20111212124834;perm=el;size=12288;type=dir;unique=807g100001; /
250 End MLST.

您要做的是解析该字符串并通过查找“type=dir”或“type=cdir”(当前目录,如“.”)或“type=pdir”(父目录,如“..”)一个正则表达式。如果你得到一个匹配,这意味着提供的路径是指一个目录。

于 2011-12-12T12:51:09.967 回答
4

FTP.dir返回一个目录列表,您可以使用回调函数对其进行解析以找出它是否是一个目录。例如,像这样:

def parse(line):
    if line[0] == 'd':
        print(line.rpartition(' ')[2])   # gives you the name of a directory

ftp.dir(parse)
于 2009-07-06T17:55:52.707 回答
4
def is_file(filename):
    return ftp.size(filename) is not None

这是有效的,因为 ftp.size 如果它是一个目录则返回 None 。

于 2009-07-06T18:01:04.833 回答
1

这就是我用来在给定目录中查找目录的方法。我将目录名称作为一个集合返回,因为我稍后会在程序中使用集合,但是您可以在最后停止创建集合,并将目录名称作为列表、元组等返回。

def get_directories(ftp_server):
    """
    Returns a set of directories in the current directory on the FTP server

    Stdout output of ftp_server.dir() is redirected to an IO object and then
    reset, because ftp_server.dir() only prints its results to stdout.

    @param ftp_server: Open connection to FTP server
    @return: Set of directory names
    """
    # Redirect stdout
    old_stdout = sys.stdout
    sys.stdout = new_stdout = StringIO()
    # Get directory listing
    ftp_server.dir()
    # Reset stdout
    sys.stdout = old_stdout

    directory_listing = new_stdout.getvalue().split("\n")
    # Directories are listed starting with "d" for "directory"
    only_directories = (x for x in directory_listing if x.startswith("d"))
    # This only deals with directory names without spaces.
    directory_names = set(dirname.split()[-1] for dirname in only_directories)
    return directory_names
于 2013-05-24T07:24:38.700 回答
1

我在处理 ftplib 时使用过这个:

import ftplib
from ftplib import FTP
ftp=FTP("ftp address")
ftp.login("user","password")

path = "/is/this/a/file/or/a/folder/"

try:
    ftp.cwd(path)
    print "it's a folder!"
except ftplib.error_perm:
    print "it's not a folder!"
于 2012-05-18T19:52:42.410 回答
1
def is_file(filename):
    current = ftp.pwd()
    try:
        ftp.cwd(filename)
    except:
        ftp.cwd(current)
        return True
    ftp.cwd(current)
    return False

这是另一个解决方案。写到一半才发现有问题。如果您没有更改到文件夹的权限,它将改为将其作为文件读取。如果您有权访问任何文件夹,它将起作用。

我仍然发布它,因为它可能会给出一些想法。

于 2009-07-06T18:49:41.723 回答
0

我找到了一个解决方案,但它可能不是最好的,我认为它可能对您有所帮助。

> def isfile(remote_name):
>     try:
>         ftp.sendcmd('MDTM ' + remote_name)
>     except:
>         return False
>     else:
>         return True

如果 'remote_name' 是常规文件,此函数将返回 TRUE,否则将返回 False。

于 2014-12-05T17:29:33.477 回答
0
def _get_file_type(self, path):
    """
Returns string parsed from MLST command
    """
    try:
        return_str = self.ftp.sendcmd('MLST ' + path)
    except BaseException as e:
        raise BaseException("No such file or directory")
    c = re.search('Type=(dir|file);', return_str)
    try:
        filetype = c.group(1)
    except AttributeError as e:
        raise BaseException("Unable to parse")
    return filetype


def is_file(self,path):
    """
Returns if a filepath is a file
    """
    filetype = self._get_file_type(path)
    if filetype == 'file':
        return True
    return False
于 2017-09-20T03:06:41.130 回答
0

True如果object是文件,此函数返回,否则返回False

def _is_file(FTP, object):
    if FTP.nlst(object) == [object]:
        return True
    else:
        return False

使用示例:

import ftplib

with ftplib.FTP(host=ftp_link, user=ftp_username, passwd=ftp_password) as FTP:
    if _is_file(FTP, object='/path/filename.extention'):
        print(object, 'is file!')
    else:
        print(object, 'is directory!')

FTP.nlst()是如何工作的?

  1. FTP.nlst(object)[object]如果object是文件则返回。
  2. FTP.nlst(object)object如果是空文件夹,则返回空列表。
  3. FTP.nlst(object)object如果是包含文件或目录的文件夹,则返回字符串列表。
于 2019-08-15T04:04:15.257 回答
0

我的整个解决方案如下所示:

def is_file(filename):
    try:
        ftp.cwd(filename)
    except Exception as e:
        if "550" in e:
            return True
    return False
于 2017-02-27T20:02:15.437 回答
0

如果要检查路径是否属于文件或目录,最好的解决方案是您已经提到的:

ftp = FTP()
ftp.connect(host, port)
ftp.login(user, pass)

# returns True if the path belongs to a file and False if it's a folder
def is_file(path):
    try:
        ftp.size(path)
        return True
    except:
        return False

但是如果要获取文件夹内的文件或文件夹列表,可以使用mlsd方法。这个方法返回一个字典,它的键是子元素的名称,它的值是另一个字典,显示每个元素的属性,在每个值中,有一个名为的键type,它显示元素的类型:

cdir: current(!?) 目录(属于.key)

pdir: 父目录(属于..key)

dir: 目录。

file: 文件!

因此,例如,此函数返回一个包含文件列表和目录列表的元组:

def ls(path):
    files_list = []
    directories_list = []
    for k, v in ftp.mlsd(path):
        if v['type'] == 'file':
            files_list.append(k)
        elif v['type'] == 'dir':
            directories_list.append(k)
    return files_list, directories_list
于 2020-01-02T08:37:31.687 回答
0
ftp_conn = FTP(host=host_name, user=user_name, passwd=password, acct='', timeout=None, source_address=None)
ftp_conn.cwd(path_ftp)
for data_dir in ftp_conn.mlsd():
    print(data_dir)

输出:

('3', {'modify': '20170719134928', 'perm': 'flcdmpe', 'type': 'dir', 'unique': '804U485826E', 'unix.group': '10000', 'unix.mode': '0755', 'unix.owner': '10754'})

see 'type': 'dir'
于 2017-07-26T07:17:56.883 回答
-3

所有文件都有一个扩展名,因此使用 split('.') 可以将其分解为大小为 2 的列表。而对于目录,使用 split('.') 后列表的大小将是 1。因此,通过检查列表的大小,我们可以确定它是文件还是目录。

os.chdir(r"path")
ftp = ftplib.FTP('ftp.some.server')
ftp.login('username','password')
filelist=ftp.nlst()
for file in filelist:
    fildir=file.split('.')
    filsize=len(fildir)
    if(filsize>1):
        ftp.retrbinary('RETR %s' %file, open(file, 'wb').write)
ftp.close()
于 2015-01-25T20:37:04.373 回答