选择性下载和提取数据 (CAB)
Posted
技术标签:
【中文标题】选择性下载和提取数据 (CAB)【英文标题】:Selective download and extraction of data (CAB) 【发布时间】:2018-09-06 16:10:25 【问题描述】:所以我特别需要下载和提取 cab 文件,但每个 cab 文件的大小都很大 > 200MB。我想有选择地从驾驶室下载文件,因为其余数据无用。
到目前为止做了这么多:
-
向服务器请求 1% 的文件。获取标头并解析它们。
根据This CAB Link获取文件列表及其偏移量。
向服务器发送 GET 请求,并将 Range 标头设置为文件 Offset 和 Offset+Size。
我能够得到响应,但它是“不可读”的,因为它被压缩了(LZX:21 - Acc to 7Zip)
无法使用 zlib 解压缩。抛出无效的标头。
我也不太明白,也无法追踪示例中显示的 CFFOLDER 或 CFDATA 导致其未压缩。
totalByteArray =b''
eofiles =0
def GetCabMetaData(stream):
global eofiles
cabMetaData=
try:
cabMetaData["CabFormat"] = stream[0:4].decode('ANSI')
cabMetaData["CabSize"] = struct.unpack("<L",stream[8:12])[0]
cabMetaData["FilesOffset"] = struct.unpack("<L",stream[16:20])[0]
cabMetaData["NoOfFolders"] = struct.unpack("<H",stream[26:28])[0]
cabMetaData["NoOfFiles"] = struct.unpack("<H",stream[28:30])[0]
# skip 30,32,34,35
cabMetaData["Files"]=
cabMetaData["Folders"]=
baseOffset = cabMetaData["FilesOffset"]
internalOffset = 0
for i in range(0,cabMetaData["NoOfFiles"]):
fileDetails =
fileDetails["Size"] = struct.unpack("<L",stream[baseOffset+internalOffset:][:4])[0]
fileDetails["UnpackedStartOffset"] = struct.unpack("<L",stream[baseOffset+internalOffset+4:][:4])[0]
fileDetails["FolderIndex"] = struct.unpack("<H",stream[baseOffset+internalOffset+8:][:2])[0]
fileDetails["Date"] = struct.unpack("<H",stream[baseOffset+internalOffset+10:][:2])[0]
fileDetails["Time"] = struct.unpack("<H",stream[baseOffset+internalOffset+12:][:2])[0]
fileDetails["Attrib"] = struct.unpack("<H",stream[baseOffset+internalOffset+14:][:2])[0]
fileName =''
for j in range(0,len(stream)):
if(chr(stream[baseOffset+internalOffset+16 +j])!='\x00'):
fileName +=chr(stream[baseOffset+internalOffset+16 +j])
else:
break
internalOffset += 16+j+1
cabMetaData["Files"][fileName] = (fileDetails.copy())
eofiles = baseOffset + internalOffset
except Exception as e:
print(e)
pass
print(cabMetaData["CabSize"])
return cabMetaData
def GetFileSize(url):
resp = requests.head(url)
return int(resp.headers["Content-Length"])
def GetCABHeader(url):
global totalByteArray
size = GetFileSize(url)
newSize ="bytes=0-"+ str(int(0.01*size))
totalByteArray = b''
cabHeader= requests.get(url,headers="Range":newSize,stream=True)
for chunk in cabHeader.iter_content(chunk_size=1024):
totalByteArray += chunk
def DownloadInfFile(baseUrl,InfFileData,InfFileName):
global totalByteArray,eofiles
if(not os.path.exists("infs")):
os.mkdir("infs")
baseCabName = baseUrl[baseUrl.rfind("/"):]
baseCabName = baseCabName.replace(".","_")
if(not os.path.exists("infs\\" + baseCabName)):
os.mkdir("infs\\"+baseCabName)
fileBytes = b''
newRange = "bytes=" + str(eofiles+InfFileData["UnpackedStartOffset"] ) + "-" + str(eofiles+InfFileData["UnpackedStartOffset"]+InfFileData["Size"] )
data = requests.get(baseUrl,headers="Range":newRange,stream=True)
with open("infs\\"+baseCabName +"\\" + InfFileName ,"wb") as f:
for chunk in data.iter_content(chunk_size=1024):
fileBytes +=chunk
f.write(fileBytes)
f.flush()
print("Saved File " + InfFileName)
pass
def main(url):
GetCABHeader(url)
cabMetaData = GetCabMetaData(totalByteArray)
for fileName,data in cabMetaData["Files"].items():
if(fileName.endswith(".txt")):
DownloadInfFile(url,data,fileName)
main("http://path-to-some-cabinet.cab")
所有文件详细信息均正确无误。我已经验证过了。
任何指导将不胜感激。我做错了吗?也许是另一种方式?
P.S : 已经看过This Post
【问题讨论】:
【参考方案1】:首先,CAB 中的数据是原始 deflate,而不是 zlib 包装的 deflate。所以你需要让 zlib 的 inflate()
在初始化时使用负的 windowBits
值解码原始 deflate。
其次,CAB 格式并不完全使用标准 deflate,因为 32K 滑动窗口字典从一个块传送到下一个块。您需要使用 inflateSetDictionary()
在每个块的开头使用从最后一个块解压缩的最后 32K 设置字典。
【讨论】:
我会调查的。但是我到目前为止所做的是否正确?文件的 uOffsets 在文件夹内指定。还有对于第一个文件setDictionary 不需要设置吗?因为之前没有解压过? 我没有时间检查您的代码。是的,一开始没有字典。历史记录在文件夹开始时被清除。以上是关于选择性下载和提取数据 (CAB)的主要内容,如果未能解决你的问题,请参考以下文章
[转]SQL SERVER2017|2019 安装程序无法与下载服务器联系。无法安装机器学习服务的问题解决方式