当前位置: 首页 > 面试题库 >

在FTP服务器上的zip文件中获取文件名,而无需下载整个存档

贲招
2023-03-14
问题内容

我在远程FTP服务器上有很多zip存档,它们的大小高达20TB。我只需要这些zip归档文件中的文件名,以便可以将它们插入我的Python脚本中。

有什么方法可以获取文件名而无需实际下载文件并将其解压缩到本地计算机上吗?如果是这样,有人可以将我定向到正确的库/软件包吗?


问题答案:

您可以实现一个类似文件的对象,该对象从FTP读取数据,而不是从本地文件读取数据。并将其传递给ZipFile构造函数,而不是(本地)文件名。

一个简单的实现可以像:

from ftplib import FTP
from ssl import SSLSocket

class FtpFile:

    def __init__(self, ftp, name):
        self.ftp = ftp
        self.name = name
        self.size = ftp.size(name)
        self.pos = 0

    def seek(self, offset, whence):
        if whence == 0:
            self.pos = offset
        if whence == 1:
            self.pos += offset
        if whence == 2:
            self.pos = self.size + offset

    def tell(self):
        return self.pos

    def read(self, size = None):
        if size == None:
            size = self.size - self.pos
        data = B""

        # based on FTP.retrbinary 
        # (but allows stopping after certain number of bytes read)
        ftp.voidcmd('TYPE I')
        cmd = "RETR {}".format(self.name)
        conn = ftp.transfercmd(cmd, self.pos)
        try:
            while len(data) < size:
                buf = conn.recv(min(size - len(data), 8192))
                if not buf:
                    break
                data += buf
            # shutdown ssl layer (can be removed if not using TLS/SSL)
            if SSLSocket is not None and isinstance(conn, SSLSocket):
                conn.unwrap()
        finally:
            conn.close()
        try:
            ftp.voidresp()
        except:
            pass
        self.pos += len(data)
        return data

然后您可以像这样使用它:

ftp = FTP(host, user, passwd)
ftp.cwd(path)

ftpfile = FtpFile(ftp, "archive.zip")
zip = zipfile.ZipFile(ftpfile)
print(zip.namelist())

上面的实现是微不足道且效率低下的。它开始下载小块数据(至少三个),以检索包含的文件列表。可以通过读取和缓存较大的块进行优化。但这应该可以给您想法。

特别是,您可以利用仅阅读清单的事实。该列表位于ZIP归档文件的和。因此,您一开始就可以下载最后(大约)10
KB的数据。这样您就可以完成read缓存中的所有呼叫。

知道这一点,您实际上可以进行一些小小的改动。由于清单位于存档的末尾,因此您实际上只能下载存档的末尾。虽然下载的ZIP将被破坏,但仍可以列出。这样,您将不需要FtpFile课程。您甚至可以将列表下载到内存(StringIO)。

zipstring = StringIO()
name = "archive.zip"
size = ftp.size(name)
ftp.retrbinary("RETR " + name, zipstring.write, rest = size - 10*2024)

zip = zipfile.ZipFile(zipstring)

print(zip.namelist())

如果BadZipfile由于10 KB太小而无法包含整个清单而导致异常,则可以使用更大的块重试代码。



 类似资料:
  • 我正试图下载一些公共数据文件。我通过screensrap获取指向文件的链接,这些文件看起来都是这样的: 我在Requests library网站上找不到任何文档。

  • 我必须从FTP服务器下载最新文件。我知道如何从我的计算机下载最新文件,但我不知道如何从FTP服务器下载。 如何从FTP服务器下载最新文件? 这是我从电脑上下载最新文件的程序 好的,使用此代码我知道最后一个文件的日期,但我如何知道这个文件的名称?????????

  • 我有一个要求,我需要下载某些。从FTP服务器压缩文件,并将存档的内容(内容是一些XML文件)推送到HDFS(Hadoop分布式文件系统)。因此,到目前为止,我正在使用acpache FTPClient连接到FTP服务器,并首先将文件下载到本地计算机。稍后将其解压缩,并给出一个方法的文件夹路径,该方法将迭代本地文件夹并将文件推送到HDFS。为了便于理解,我还在下面附加了一些代码片段。 现在,这种方法

  • 你好,我有错误,如java.lang.NullPointerException上OutputStream out=ftp.storeFileStream(路径);. 你能帮帮我吗?代码编写了第一个图像,并完全停止了编写。这是我的方法代码。。。。。。。。 我将发布两个单独的代码。事实上这是一种方法。 这是NPE错误! java.lang.NullPointerException atcom.scm.

  • 我有下面的代码从mkyong得到,到本地的zip文件。但,我的要求是在服务器上压缩文件,并需要下载。谁能帮忙吗。 写入zipFiles的代码: 我可以在fileoutputstream这里提供什么?内容文件和导航文件是我从代码中创建的文件。

  • 问题内容: 我使用以下代码从ftp下载文件到内存: 如何使它直接将文件发送给用户(浏览器)而不保存到磁盘,也无需重定向到ftp服务器? 问题答案: 只需删除输出缓冲(和其他)。 仅使用此: 虽然如果要添加标题,则必须先使用来查询文件大小: (添加错误处理)