Tarfile / Zipfile extractall()更改某些文件的文件名

时间:2019-03-25 14:23:55

标签: python file zip tar

您好,我目前正在使用一种必须提取一些.tar文件的工具。

在大多数情况下效果很好,但我有一个问题:

某些.tar和.zip文件的名称包含“非法”字符(例如“ .ex”:“)。 该程序必须在Windows机器上运行,所以我必须对此进行处理。

如果其中包含“:”或另一个非法的Windows字符,是否可以更改提取的输出中某些文件的名称。

我当前的实现方式:

conflicts.Abort

所以目前我只是忽略了这些输出,这并不理想。

为了更好地描述我的要求,我可以举一个小例子:

def read_zip(filepath, extractpath):
    with zipfile.ZipFile(filepath, 'r') as zfile:
        contains_bad_char = False
        for finfo in zfile.infolist():
            if ":" in finfo.filename:
                contains_bad_char = True
        if not contains_bad_char:
            zfile.extractall(path=extractpath)


def read_tar(filepath, extractpath):
    with tarfile.open(filepath, "r:gz") as tar:
        contains_bad_char = False
        for member in tar.getmembers():
            if ":" in member.name:
                contains_bad_char = True
        if not contains_bad_char:
            tar.extractall(path=extractpath)

应提取到

file_with_files.tar -> small_file_1.txt
                    -> small_file_2.txt
                    -> annoying:file_1.txt
                    -> annoying:file_1.txt

唯一的解决方案是遍历压缩文件中的每个文件对象并一步一步提取,还是有一个更优雅的解决方案?

1 个答案:

答案 0 :(得分:1)

根据[Python 3]: ZipFile.extract(member, path=None, pwd=None)

  

在Windows上,非法字符(:<>|"?* )替换为下划线(_)。

所以,事情已经解决了:

>>> import os
>>> import zipfile
>>>
>>> os.getcwd()
'e:\\Work\\Dev\\StackOverflow\\q055340013'
>>> os.listdir()
['arch.zip']
>>>
>>> zf = zipfile.ZipFile("arch.zip")
>>> zf.namelist()
['file0.txt', 'file:1.txt']
>>> zf.extractall()
>>> zf.close()
>>>
>>> os.listdir()
['arch.zip', 'file0.txt', 'file_1.txt']

快速浏览 tarfile (源文件和文档)并没有发现类似的内容(如果没有的话, .tar 格式主要用于 Nix ),因此您必须手动进行操作。事情并没有我预想的那么简单,因为 tarfile 不能像 zipfile 那样提供使用不同名称提取成员的可能性。
无论如何,这是一段代码(我有 zipfile tarfile 作为灵感或灵感来源):

def read_tar(filepath, extractpath="."):
    win_illegal = ':<>|"?*'
    table = str.maketrans(win_illegal, '_' * len(win_illegal))
    with tarfile.open(filepath, "r:gz") as tar:
        for member in tar.getmembers():
            if member.isdir():
                os.makedirs(member.path.translate(table))
            else:
                with open(os.path.join(extractpath, member.path.translate(table)), "wb") as fout:
                    fout.write(tarfile.ExFileObject(tar, member).read())

请注意,上面的代码适用于简单的 .tar 文件(具有简单的成员,包括目录),但我没有对其健壮性进行测试

@ EDIT0

添加了目录处理。

@ EDIT1

已提交[Python.Bugs]: tarfile: handling Windows (path) illegal characters in archive member names
我不知道它的结果如何,因为我提交了一些更严重的问题(并针对它们进行了修复)(在我的 PoV 上),但是对于出于各种原因,他们被拒绝了。