python - 在 Ubuntu 与 Windows 中解压缩相同文件时的不同目录结构
问题描述
我正在尝试提取 zip 文件的内容,可以在此处查看:
https://www.geoboundaries.org/data/geoBoundaries-2_0_0/NGA/ADM1/geoBoundaries-2_0_0-NGA-ADM1-all.zip
在 Ubuntu 18.04.04 上,通过右键菜单中的“提取”选项,我从该 zip 文件中获得了一个文件夹结构,其中包括各种空文件夹和目录,以及不同的父级。如果我使用 7Zip(在 Windows 或同一个 linux 机器上)解压缩相同的文件,我会得到 6 个文件的预期结果。
那么 - 这里有什么区别?
(注意我已经有了一个解决方案——shutil 存档工作——只是试图理解不同的行为)。
这是当前用于构建相关拉链的代码(python):
def zipdir(dirPath=None, zipFilePath=None, includeDirInZip=False, citeUsePath=False):
if not zipFilePath:
zipFilePath = dirPath + ".zip"
if not os.path.isdir(dirPath):
raise OSError("dirPath argument must point to a directory. "
"'%s' does not." % dirPath)
parentDir, dirToZip = os.path.split(dirPath)
def trimPath(path):
archivePath = path.replace(parentDir, "", 1)
if parentDir:
archivePath = archivePath.replace(os.path.sep, "", 1)
if not includeDirInZip:
archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1)
return os.path.normcase(archivePath)
outFile = zipfile.ZipFile(zipFilePath, "w",compression=zipfile.ZIP_DEFLATED)
for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath):
for fileName in fileNames:
if(not fileName == zipFilePath.split("/")[-1]):
filePath = os.path.join(archiveDirPath, fileName)
outFile.write(filePath, trimPath(filePath))
outFile.write(citeUsePath, os.path.basename(citeUsePath))
outFile.close()
解决方案
zip 文件geoBoundaries-2_0_0-NGA-ADM1-all.zip
是非标准的。
在 Linux 上,unzip
认为有 5 个文件没有路径组件
$ unzip -l geoBoundaries-2_0_0-NGA-ADM1-all.zip
Archive: geoBoundaries-2_0_0-NGA-ADM1-all.zip
Length Date Time Name
--------- ---------- ----- ----
374953 2020-01-15 21:04 geoBoundaries-2_0_0-NGA-ADM1-shp.zip
1512980 2020-01-15 21:04 geoBoundaries-2_0_0-NGA-ADM1.geojson
804 2020-01-15 21:04 geoBoundaries-2_0_0-NGA-ADM1-metaData.json
750 2020-01-15 21:04 geoBoundaries-2_0_0-NGA-ADM1-metaData.txt
4656 2020-01-15 21:04 CITATION-AND-USE-geoBoundaries-2_0_0.txt
--------- -------
1894143 5 files
如果我然后尝试提取内容,我会收到很多警告。
$ unzip geoBoundaries-2_0_0-NGA-ADM1-all.zip
Archive: geoBoundaries-2_0_0-NGA-ADM1-all.zip
geoBoundaries-2_0_0-NGA-ADM1-shp.zip: mismatching "local" filename (release/geoBoundaries-2_0_0/NGA/ADM1/geoBoundaries-2_0_0-NGA-ADM1-shp.zip),
continuing with "central" filename version
inflating: geoBoundaries-2_0_0-NGA-ADM1-shp.zip
geoBoundaries-2_0_0-NGA-ADM1.geojson: mismatching "local" filename (release/geoBoundaries-2_0_0/NGA/ADM1/geoBoundaries-2_0_0-NGA-ADM1.geojson),
continuing with "central" filename version
inflating: geoBoundaries-2_0_0-NGA-ADM1.geojson
geoBoundaries-2_0_0-NGA-ADM1-metaData.json: mismatching "local" filename (release/geoBoundaries-2_0_0/NGA/ADM1/geoBoundaries-2_0_0-NGA-ADM1-metaData.json),
continuing with "central" filename version
inflating: geoBoundaries-2_0_0-NGA-ADM1-metaData.json
geoBoundaries-2_0_0-NGA-ADM1-metaData.txt: mismatching "local" filename (release/geoBoundaries-2_0_0/NGA/ADM1/geoBoundaries-2_0_0-NGA-ADM1-metaData.txt),
continuing with "central" filename version
inflating: geoBoundaries-2_0_0-NGA-ADM1-metaData.txt
CITATION-AND-USE-geoBoundaries-2_0_0.txt: mismatching "local" filename (tmp/CITATION-AND-USE-geoBoundaries-2_0_0.txt),
continuing with "central" filename version
inflating: CITATION-AND-USE-geoBoundaries-2_0_0.txt
分析
zip 文件中每个条目的详细信息(包括文件名)存储两次。一次在 a 中local-header
,直接在压缩数据之前,再次在central-header
文件末尾的 a 中。因此,对于存储在 zip 文件中的每个文件,都会有一对local-header
/central-header
字段。这些字段对中的数据应该(大部分)相同。
在这种情况下,它们不是。
例如,考虑 的central-header
条目geoBoundaries-2_0_0-NGA-ADM1-shp.zip
。匹配local-header
有release/geoBoundaries-2_0_0/NGA/ADM1/geoBoundaries-2_0_0-NGA-ADM1-shp.zip
.
此 zip 文件中的所有条目也是如此。
鉴于这是一个非标准/无效的 zip 文件,解压缩时的行为将取决于解压缩实用程序是否使用central-header
条目中的数据来确定文件名,或者它是否使用local-header
.
看起来 Ubuntu 正在使用这些local-header
字段,而 7zip 使用这些central-header
字段。
作为参考,zip 文件的规范是APPNOTE.TXT
推荐阅读
- c++ - 使用 std::unique_ptr 的通用单链表,Microsoft Visual Studio C++ 中的未知未编译错误
- php - 外部变量在类内部定义
- shell - 在 JSON 文件中查找和替换
- firebase - 在 Firebase Cloud Functions 上发出 API 请求
- terminal - Atom 中的拆分终端
- java - 如何将我自己的图片添加到android背景
- python - “SyntaxError: invalid syntax” 总是在带有 micro:bit 的 REPL 模式下显示在 mu-editor 上
- python - Django - 使用 pk_url_kwarg 选择性地查询模型
- amazon-web-services - Amazon SES 从 000-dsds-dss@amazonses.com 发送电子邮件,而不是配置的域
- python - 身份验证 OneDrive API Python