如果您在 linux 和 windows 之间共享文件,python zipfile 库会出现问题
Problem with the python zipfile library if you share a file between linux and windows
zipfile module 使用 python 管理 .zip 文件非常有趣。
但是,如果 .zip 文件是在 linux 系统或 macOS 上创建的,则分隔符当然是“/”,如果我们尝试在 Windows 系统上使用此文件可能是个问题,因为分隔符是“\”。
因此,例如,如果我们尝试确定 .zip 文件中压缩的目录根目录,我们可以这样想:
from zipfile import ZipFile, is_zipfile
import os
if is_zipfile(filename):
with ZipFile(filename, 'r') as zip_ref:
packages_name = [member.split(os.sep)[0] for member in zip_ref.namelist()
if (len(member.split(os.sep)) == 2 and not
member.split(os.sep)[-1])]
但在这种情况下,我们总是得到 packet_name = [],因为 os.sep 是“\”,而由于压缩是在 linux 系统上完成的,所以路径相当 'foo1/foo2'.
为了管理所有情况(在 linux 系统上压缩并在 Windows 系统上使用或相反),我想使用:
from zipfile import ZipFile, is_zipfile
import os
if is_zipfile(filename):
with ZipFile(filename, 'r') as zip_ref:
if all([True if '/' in el else
False for el in zip_ref.namelist()]):
packages_name = [member.split('/')[0] for member in zip_ref.namelist()
if (len(member.split('/')) == 2 and not
member.split('/')[-1])]
else:
packages_name = [member.split('\')[0] for member in zip_ref.namelist()
if (len(member.split('\')) == 2 and not
member.split('\')[-1])]
你怎么看这个?
有没有更直接或更 pythonic 的方式来完成这项工作?
感谢@snakecharmerb 的回答和阅读他提出的link,我才明白。谢谢@snakecharmerb 给我指路......
事实上,确实如 link 提议中所述,内部 zipfile 仅使用 '/' 并且这与所使用的 OS 无关。因为我喜欢具体地看事情,所以我做了这个小测试:
在 Windows OS 上,我用通常的方法创建了这个 OS (不是在命令行中)一个包含这个的文件 testZipWindows.zip树结构:
- testZipWindows
- foo1.txt
- InFolder
- foo2.txt
我在 linux OS 上为 testZipFedora.zip 存档做了同样的事情(并且没有使用命令行):
- testZipFedora
- foo1.txt
- InFolder
- foo2.txt
这是结果:
$ python3
Python 3.7.9 (default, Aug 19 2020, 17:05:11)
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from zipfile import ZipFile
>>> with ZipFile('/home/servoz/Desktop/test/testZipWindows.zip', 'r') as WinZip:
... WinZip.namelist()
...
['testZipWindows/', 'testZipWindows/foo1.txt', 'testZipWindows/InFolder/', 'testZipWindows/InFolder/foo2.txt']
>>> with ZipFile('/home/servoz/Desktop/test/testZipFedora.zip', 'r') as fedZip:
... fedZip.namelist()
...
['testZipFedora/', 'testZipFedora/foo1.txt', 'testZipFedora/InFolder/', 'testZipFedora/InFolder/foo2.txt']
所以一切都亮了!我们确实必须使用 os.path.sep 才能在多平台中正常工作,但是当我们处理 zipfile 库时,绝对有必要使用 '/' 作为分隔符而不是 os.sep(或 os.path.sep)。那是我的错误!!!
因此,对于我的第一个 post 示例,以多平台方式使用的代码只是:
from zipfile import ZipFile, is_zipfile
import os
if is_zipfile(filename):
with ZipFile(filename, 'r') as zip_ref:
packages_name = [member.split('/')[0] for member in zip_ref.namelist()
if (len(member.split('/')) == 2 and not
member.split('/')[-1])]
而且不是我想象的所有无用的东西...
zipfile module 使用 python 管理 .zip 文件非常有趣。
但是,如果 .zip 文件是在 linux 系统或 macOS 上创建的,则分隔符当然是“/”,如果我们尝试在 Windows 系统上使用此文件可能是个问题,因为分隔符是“\”。 因此,例如,如果我们尝试确定 .zip 文件中压缩的目录根目录,我们可以这样想:
from zipfile import ZipFile, is_zipfile
import os
if is_zipfile(filename):
with ZipFile(filename, 'r') as zip_ref:
packages_name = [member.split(os.sep)[0] for member in zip_ref.namelist()
if (len(member.split(os.sep)) == 2 and not
member.split(os.sep)[-1])]
但在这种情况下,我们总是得到 packet_name = [],因为 os.sep 是“\”,而由于压缩是在 linux 系统上完成的,所以路径相当 'foo1/foo2'.
为了管理所有情况(在 linux 系统上压缩并在 Windows 系统上使用或相反),我想使用:
from zipfile import ZipFile, is_zipfile
import os
if is_zipfile(filename):
with ZipFile(filename, 'r') as zip_ref:
if all([True if '/' in el else
False for el in zip_ref.namelist()]):
packages_name = [member.split('/')[0] for member in zip_ref.namelist()
if (len(member.split('/')) == 2 and not
member.split('/')[-1])]
else:
packages_name = [member.split('\')[0] for member in zip_ref.namelist()
if (len(member.split('\')) == 2 and not
member.split('\')[-1])]
你怎么看这个? 有没有更直接或更 pythonic 的方式来完成这项工作?
感谢@snakecharmerb 的回答和阅读他提出的link,我才明白。谢谢@snakecharmerb 给我指路...... 事实上,确实如 link 提议中所述,内部 zipfile 仅使用 '/' 并且这与所使用的 OS 无关。因为我喜欢具体地看事情,所以我做了这个小测试:
在 Windows OS 上,我用通常的方法创建了这个 OS (不是在命令行中)一个包含这个的文件 testZipWindows.zip树结构:
- testZipWindows
- foo1.txt
- InFolder
- foo2.txt
- testZipWindows
我在 linux OS 上为 testZipFedora.zip 存档做了同样的事情(并且没有使用命令行):
- testZipFedora
- foo1.txt
- InFolder
- foo2.txt
- testZipFedora
这是结果:
$ python3
Python 3.7.9 (default, Aug 19 2020, 17:05:11)
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from zipfile import ZipFile
>>> with ZipFile('/home/servoz/Desktop/test/testZipWindows.zip', 'r') as WinZip:
... WinZip.namelist()
...
['testZipWindows/', 'testZipWindows/foo1.txt', 'testZipWindows/InFolder/', 'testZipWindows/InFolder/foo2.txt']
>>> with ZipFile('/home/servoz/Desktop/test/testZipFedora.zip', 'r') as fedZip:
... fedZip.namelist()
...
['testZipFedora/', 'testZipFedora/foo1.txt', 'testZipFedora/InFolder/', 'testZipFedora/InFolder/foo2.txt']
所以一切都亮了!我们确实必须使用 os.path.sep 才能在多平台中正常工作,但是当我们处理 zipfile 库时,绝对有必要使用 '/' 作为分隔符而不是 os.sep(或 os.path.sep)。那是我的错误!!!
因此,对于我的第一个 post 示例,以多平台方式使用的代码只是:
from zipfile import ZipFile, is_zipfile
import os
if is_zipfile(filename):
with ZipFile(filename, 'r') as zip_ref:
packages_name = [member.split('/')[0] for member in zip_ref.namelist()
if (len(member.split('/')) == 2 and not
member.split('/')[-1])]
而且不是我想象的所有无用的东西...