首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在FTP服务器上获取zip文件中的文件名,而不下载整个归档文件

在FTP服务器上获取zip文件中的文件名,而不下载整个归档文件
EN

Stack Overflow用户
提问于 2018-12-04 07:44:53
回答 1查看 0关注 0票数 0

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

有没有办法只获取文件名,而不实际下载文件并在我的本地机器上提取它们?如果是这样的话,有人能告诉我正确的库/包吗?

EN

回答 1

Stack Overflow用户

发布于 2018-12-04 17:42:43

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

一个简单的实现可以是:

代码语言:javascript
复制
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
        print("seek {}".format(self.pos))

    def tell(self):
        print("tell {}".format(self.pos))
        return self.pos

    def read(self, size = None):
        if size == None:
            size = self.size - self.pos
        print("read {}".format(size))
        data = ""

        # 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()
        ftp.voidresp()
        print("read {}".format(len(data)))
        return data

然后你可以:

代码语言:javascript
复制
ftp = FTP(host, user, passwd)
ftp.cwd(path)

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

上述实现相当简单且效率低下。它开始大量(至少三次)下载小块数据以检索包含文件的列表。它可以通过读取和缓存更大的块来优化。但它应该给你的想法。

特别是你可以利用你将只阅读一个列表的事实。该列表位于ZIP存档和。因此,您可以在开始时下载最后(大约)10 KB的数据。并且您将能够完成read缓存中的所有呼叫。

知道了,你实际上可以做一个小hack。由于列表位于归档的末尾,因此您实际上只能下载归档的末尾。虽然下载的ZIP将被破坏,但仍然可以列出。这样,你就不需要FtpFile了。

代码语言:javascript
复制
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太小而无法包含整个列表而出现异常,则可以使用更大的块重试代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100006212

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档