代码之家  ›  专栏  ›  技术社区  ›  Mykhailo Seniutovych

Python zipfile不解压缩windows zip存档的文件夹

  •  1
  • Mykhailo Seniutovych  · 技术社区  · 6 年前

    Windows 使用此工具的机器 System.IO.Compression.ZipFile Linux 机器(确切地说是raspberry-pi),它必须解压缩归档文件并创建所有必要的文件夹和文件。我在用 Python 3.5.0 zipfile

    import zipfile
    
    zip = zipfile.ZipFile("MyArchive.zip","r")
    zip.extractall()
    zip.close()
    

    现在,当我运行这段代码而不是得到一个很好的解压目录树时,我得到了根目录中所有文件的奇怪名称,比如 Folder1\Folder2\MyFile.txt .

    \ 而在Linux上则是 / ,蟒蛇 拉链 作为文件名的一部分而不是目录分隔符。还要注意的是,当我手动(而不是通过python代码)提取这个归档文件时,所有的文件夹都是按预期创建的,所以看起来这肯定是一个问题 拉链 图书馆。另一个注意事项是,对于使用不同工具创建的zip归档文件(不是 系统IO压缩ZipFile先生 )使用相同的python代码可以正常工作。

    对发生了什么以及如何解决它有什么见解吗?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Mad Physicist    6 年前

    现在的情况是,虽然Windows可以同时识别 \ ( path.sep )以及 / path.altsep )作为路径分隔符,Linux只能识别 / 路径.sep ).

    作为 @blhsing's answer ZipFile 路径.sep 被认为是有效的分隔符字符。这意味着在Linux上, \ os.altsep \

    如果你走上修改的道路 拉链 \ 路径.sep / 反正总是已经变了。那样的话, / , \ 还有可能 将全部转换为 路径.sep . 这就是命令行工具所要做的。

        2
  •  1
  •   blhsing    6 年前

    zipfile module ,其中有以下行 ZipFile._extract_member() 盲目替换 '/' '\\'

    arcname = member.filename.replace('/', os.path.sep)
    

    您可以通过重写 ZipFile.\u extract\u member()

    from zipfile import ZipFile, ZipInfo
    import shutil
    import os
    def _extract_member(self, member, targetpath, pwd):
        """Extract the ZipInfo object 'member' to a physical
           file on the path targetpath.
        """
        if not isinstance(member, ZipInfo):
            member = self.getinfo(member)
    
        if os.path.sep == '/':
            arcname = member.filename.replace('\\', os.path.sep)
        else:
            arcname = member.filename.replace('/', os.path.sep)
    
        if os.path.altsep:
            arcname = arcname.replace(os.path.altsep, os.path.sep)
        # interpret absolute pathname as relative, remove drive letter or
        # UNC path, redundant separators, "." and ".." components.
        arcname = os.path.splitdrive(arcname)[1]
        invalid_path_parts = ('', os.path.curdir, os.path.pardir)
        arcname = os.path.sep.join(x for x in arcname.split(os.path.sep)
                                   if x not in invalid_path_parts)
        if os.path.sep == '\\':
            # filter illegal characters on Windows
            arcname = self._sanitize_windows_name(arcname, os.path.sep)
    
        targetpath = os.path.join(targetpath, arcname)
        targetpath = os.path.normpath(targetpath)
    
        # Create all upper directories if necessary.
        upperdirs = os.path.dirname(targetpath)
        if upperdirs and not os.path.exists(upperdirs):
            os.makedirs(upperdirs)
    
        if member.is_dir():
            if not os.path.isdir(targetpath):
                os.mkdir(targetpath)
            return targetpath
    
        with self.open(member, pwd=pwd) as source, \
                open(targetpath, "wb") as target:
            shutil.copyfileobj(source, target)
    
        return targetpath
    ZipFile._extract_member = _extract_member