将解压缩的文件写入从Web服务器获取的磁盘

时间:2014-07-27 13:44:01

标签: python zip gzip python-requests 7zip

我可以获得content-encodinggzip的文件。

这是否意味着服务器将其存储为压缩文件,或者对于存储为压缩zip或7z文件的文件也是如此?

如果是这样(其中durl是一个zip文件)

>>> durl = 'https://db.tt/Kq0byWzW'
>>> dresp = requests.get(durl, allow_redirects=True, stream=True)
>>> dresp.headers['content-encoding']
'gzip'

>>> r = requests.get(durl, stream=True)
>>> data = r.raw.read(decode_content=True)

但数据出来是空的,而我想在旅途中将zip文件解压缩到磁盘上!

3 个答案:

答案 0 :(得分:0)

您需要来自请求文件的内容才能编写它。 确认工作:

import requests
durl = 'https://db.tt/Kq0byWzW'
dresp = requests.get(durl, allow_redirects=True, stream=True)
dresp.headers['content-encoding']

file = open('test.html', 'w')
file.write(dresp.text)

答案 1 :(得分:0)

首先,durl不是zip文件,而是一个dropbox登录页面。所以你要看的是使用gzip编码发送的HTML。如果您使用gzip从原始套接字解码数据的位置,您只需获取HTML。因此,使用raw实际上只是隐藏了你不小心去了另一个文件而不是你想到的文件。

根据您要求的https://plus.google.com/u/0/100262946444188999467/posts/VsxftxQnRam

  

有没有人知道将压缩文件直接写入磁盘到解压缩状态?

我认为你真的想要获取一个zip并将其直接解压缩到一个目录而不先存储它。为此,您需要使用https://docs.python.org/2/library/zipfile.html

虽然在这一点上问题变成了请求的响应实际上是不可寻的,但是zipfile需要哪个才能工作(它将要做的第一件事就是寻找文件的末尾以确定它有多长是)。

要解决此问题,您需要将响应包装在像object这样的文件中。我个人建议使用tempfile.SpooledTemporaryFile设置最大尺寸。这样,如果文件大于您的预期,您的代码将切换到将内容写入磁盘。

import requests
import tempfile
import zipfile

KB = 1<<10
MB = 1<<20

url = '...' # Set url to the download link.

resp = requests.get(url, stream=True)
with tmp as tempfile.SpooledTemporaryFile(max_size=500*MB):
    for chunk in resp.iter_content(4*KB):
        tmp.write(chunk)
    archive = zipfile.ZipFile(tmp)
    archive.extractall(path)

使用io.BytesIO的相同代码:

resp = requests.get(url, stream=True)
tmp = io.BytesIO()
for chunk in resp.iter_content(4*KB):
    tmp.write(chunk)
archive = zipfile.ZipFile(tmp)
archive.extractall(path)

答案 2 :(得分:0)

您必须区分content-encoding(不要与transfer-encoding混淆)和content-type

它的要点是content-type是您尝试获取的资源的媒体类型(真实文件类型)。 content-encoding是在将其发送给客户端之前应用于它的任何修改。

因此,我们假设您想获得名为“foo.txt”的资源。它可能具有text/plain的内容类型。在添加中,可以通过网络发送时修改数据。这是content-encoding。因此,通过上面的示例,您可以拥有text/plain的内容类型和content-encoding的{​​{1}}。这意味着在服务器将文件发送到线路之前,它将使用gzip动态压缩它。所以遍历网络的唯一字节是压缩的。不是原始文件的原始字节(gzip)。

客户端的工作就是相应地处理这些标题。

现在,我不是100%确定foo.txt,或者底层python库这样做但是他们很可能会这样做。如果没有,Python附带一个默认的gzip library,所以你可以自己做,没有问题。

考虑到上述情况,回答您的问题:不,拥有requests的“内容编码”并不意味着远程资源是zip文件。包含该信息的字段为gzip(根据您的问题,根据使用的实际压缩算法,其值可能为content-typeapplication/zip

如果您无法根据application/x-7z-compressed字段(f.ex.,如果它是content-type)确定真实文件类型,则可以将文件保存到磁盘,然后打开十六进制编辑器。对于application/octet-stream文件,您应该在某处看到字节序列7z。最有可能在文件的开头或EOF-112字节。如果是37 7a bc af 27 1c文件,则文件开头应为gzip

鉴于您在1f 8b字段中有gzip:如果您收到content-encoding个文件,则可以确定7z已解析requests并且为你妥善解码。如果你得到一个content-encoding文件,那可能意味着两件事。 gzip未解码任何内容,文件确实是requests文件,因为它可能是使用gzip编码发送的gzip文件。这意味着它会被双重压缩。这没有任何意义,但是,取决于服务器,这仍然可能发生。

您可以尝试在控制台上运行gzip,看看你得到了什么。