python 3.7 中的 tarfile 过滤器

tarfile filter in python 3.7

这是我为了测试而分离出来的备份脚本的一部分。这曾经在 python 3.6 中工作,但我在 python 3.7 中遇到错误。我查看了文档,但无法真正弄清楚发生了什么变化。

#! /usr/bin/python

import os
import tarfile
import arrow


stmp = arrow.now().format('YYYY-MM-DD')
backup_path = "/home/akya/playground/"

###########################################################
# Functions
###########################################################

def exclude_function(filename):
    if filename in exclude_files or os.path.splitext(filename)[1] in exclude_files:
        return True
    else:
        return False

def compress():
    with tarfile.open(myfile, "w:gz") as tar:
        for name in L:
            tar.add(name, filter=exclude_function)

path1 = "/home/akya/playground/test"
backup_name = "test-"

L = [path1]
exclude_files = [".sh", ".html", ".json", "/home/akya/playground/test/.git"]
myfile = str(backup_path + backup_name + stmp + ".tar.gz")

compress()

我希望 tarfile 排除 exclude_files 中的任何扩展名和路径。这就是我得到的

Traceback (most recent call last):
  File "exec.py", line 33, in <module>
    compress()
  File "exec.py", line 24, in compress
    tar.add(name, filter=exclude_function)
  File "/usr/lib/python3.7/tarfile.py", line 1934, in add
    tarinfo = filter(tarinfo)
  File "exec.py", line 16, in exclude_function
    if filename in exclude_files or os.path.splitext(filename)[1] in exclude_files:
  File "/usr/lib/python3.7/posixpath.py", line 122, in splitext
    p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not TarInfo

任何人都可以指出所需的更改吗?或者更好的过滤器使用方法?

filter 回调将 TarInfo 结构传递给您的回调,因此您可以按名称以外的其他内容进行过滤:日期、大小、修改时间(看起来很像 stat 对象)...

此外,它不能那样工作(returning 布尔值),如果你想排除这个条目,你必须 return None:

TarFile.add(name, arcname=None, recursive=True, *, filter=None)

... If filter is given, it should be a function that takes a TarInfo object argument and returns the changed TarInfo object. If it instead returns None the TarInfo object will be excluded from the archive. See Examples for an example.

在您的情况下,只需选择 .name 字段和 return None 如果匹配您的过滤器。否则 return 与您收到的相同 tarinfo 结构。

def exclude_function(tarinfo):
    filename = tarinfo.name
    return None if filename in exclude_files or os.path.splitext(filename)[1] in exclude_files else tarinfo

(请注意,我不知道为什么它在早期版本中对你有用,也许你添加了 or os.path.splitext(filename)[1] in exclude_files 部分,它表明类型不正确 - 第一个 in 测试不会'即使对象类型错误也不会崩溃——但这是正确的做法)