Python脚本“键错误:“找不到文件名'xxxxx.tar.gz'"

iecba09b  于 2023-02-14  发布在  Python
关注(0)|答案(1)|浏览(119)

我正在编写一个Python备份脚本,该脚本将源目录归档到一个压缩的tar文件,然后(要验证备份,)将其解压缩到/tmp并进行比较将提取的文件与源目录中的对应文件进行比较(校验和)。在备份部分,如果在命令行中指定了要备份的目录,则一切正常。否则,脚本询问用户是否要备份当前目录。2如果回答是,则会出现以下错误:
追溯(最近调用最后调用):文件"/home/me/scripts/dir1/../www.example.com ",第89行,在〈模块信息= tar. getmember(os. path. relpath(file_path,backup_directory))中文件"/usr/lib/python3.10/tarfile. py",第1813行,在getmember中引发键错误("文件名% r未找到" % name)键错误:backup.py", line 89, in <module info = tar.getmember(os.path.relpath(file_path, backup_directory)) File "/usr/lib/python3.10/tarfile.py", line 1813, in getmember raise KeyError("filename %r not found" % name) KeyError: "filename 'Jupiter-home-me-scripts-dir1-230209-2014.tar.gz' not found"
以下是脚本的备份部分:

import os
import sys
import datetime
import socket
import time
import tarfile
import shutil
import hashlib
import fnmatch

debug = 1
CURRENT_TIME = datetime.datetime.now().strftime("%y%m%d-%H%M")

HOSTNAME = socket.gethostname()
LOGFILE = "BACKUP" + "-" + HOSTNAME + "-" + CURRENT_TIME + ".log"
CURRENT_DIRECTORY = os.getcwd()

def log_message(message, logfile=LOGFILE):
    with open(logfile, "a") as f:
        f.write(f"{message}\n")

def debug_message(message):
    if debug == 1:
        print(f"DEBUG: {message}")

CURRENT_DIRECTORY = os.getcwd()

log_message("Backup started at " + str(CURRENT_TIME))
debug_message("Backup started at " + str(CURRENT_TIME))

# sys.exit()

if len(sys.argv) < 2:
    # directory to backup was not specified on the command line
    confirm = input("No directory specified. Backup current directory '" + CURRENT_DIRECTORY + "'? (y/n) ")
    if confirm != 'y':
        sys.exit()
    else:
        # user chose to use the current directory
        debug_message("1011: user chose to backup current directory " + str(CURRENT_DIRECTORY))
        directory = CURRENT_DIRECTORY
else:
    # directory to backup was specified on the command line
    directory = sys.argv[1]

if os.path.isabs(directory):
    if os.path.isdir(directory):
        debug_message("1013: " + str(directory) + " is a full path and exists.")
        backup_directory = directory
    else:
        debug_message("1014: " + str(directory) + " is a full path but does not exist.")
        sys.exit()
else:
# Check if the directory exists as a subdirectory of the current path
    full_path = os.path.join(os.getcwd(), directory)
    if os.path.isdir(full_path):
        debug_message("1015: " + str(directory) + " exists as a subdirectory of the current path at " + str(full_path))
        backup_directory = full_path
    else:
        debug_message("1016: " + str(directory) + " does not exist as a subdirectory of the current directory")
        sys.exit()

debug_message("1020: backup_directory = " + str(backup_directory))
log_message("Backup directory = " + str(backup_directory))

if not os.listdir(backup_directory):
    debug_message("1030: Error: backup directory ({backup_directory}) is empty")
    sys.exit()

backup_source = backup_directory.replace("/", "-")
HOSTNAME = socket.gethostname()
backup_file = HOSTNAME + backup_source + "-" + CURRENT_TIME + ".tar.gz"

debug_message("1040: backup_directory = " + str(backup_directory))
debug_message("1050: backup_file = " + str(backup_file))

with tarfile.open(backup_file, "w:gz") as tar:
    for root, dirs, files in os.walk(backup_directory):
        for file in files:
            file_path = os.path.join(root, file)
            tar.add(file_path, arcname=os.path.relpath(file_path, backup_directory), recursive=False)
            info = tar.getmember(os.path.relpath(file_path, backup_directory))
            info.uid = os.stat(file_path).st_uid
            info.gid = os.stat(file_path).st_gid
            info.mode = os.stat(file_path).st_mode
    tar.close()

shutil.copystat(backup_directory, backup_file)

print("Backup created: ", CURRENT_DIRECTORY + "/" + backup_file)

我显然漏掉了一些东西,但在我看来,用户指定目录或只是确认使用当前目录应该没有区别,无论哪种方式,它都将backup_directory变量传递给脚本的其余部分。

  • 调试输出-命令行上传递的备份目录:*
DEBUG: Backup started at 230209-2013 
DEBUG: 1015: dir1 exists as a subdirectory of the current path at /home/me/scripts/dir1 
DEBUG: 1020: backup_directory = /home/me/scripts/dir1 
DEBUG: 1040: backup_directory = /home/me/scripts/dir1 
DEBUG: 1050: backup_file = Jupiter-home-me-scripts-dir1-230209-2013.tar.gz 
Backup created: 
/home/me/scripts/Jupiter-home-me-scripts-dir1-230209-2013.tar.gz
  • 调试输出-备份目录在命令行上传递,用户选择备份当前目录:*
DEBUG: Backup started at 230209-2117
No directory specified. Backup current directory '/home/me/scripts'? (y/n) y
DEBUG: 1011: user chose to backup current directory /home/me/scripts
DEBUG: 1013: /home/me/scripts is a full path and exists.
DEBUG: 1020: backup_directory = /home/me/scripts
DEBUG: 1040: backup_directory = /home/me/scripts
DEBUG: 1050: backup_file = Jupiter-home-me-scripts-230209-2117.tar.gz
Traceback (most recent call last):
  File "/home/me/scripts/backup.py", line 89, in <module>
    info = tar.getmember(os.path.relpath(file_path, backup_directory))
  File "/usr/lib/python3.10/tarfile.py", line 1813, in getmember
    raise KeyError("filename %r not found" % name)
KeyError: "filename 'Jupiter-home-me-scripts-230209-2117.tar.gz' not found"
eblbsuwk

eblbsuwk1#

我设法重现和调试您的问题。你是对的,没有区别是否使用当前目录。它可以重现两种方式。
麻烦的代码是这样的:

with tarfile.open(backup_file, "w:gz") as tar:
    for root, dirs, files in os.walk(backup_directory):
        for file in files:
            file_path = os.path.join(root, file)
            tar.add(file_path, arcname=os.path.relpath(file_path, backup_directory), recursive=False)
            info = tar.getmember(os.path.relpath(file_path, backup_directory))
            info.uid = os.stat(file_path).st_uid
            info.gid = os.stat(file_path).st_gid
            info.mode = os.stat(file_path).st_mode
    tar.close()

如果您要备份创建tar.gz归档文件的目录,则最终会尝试将归档文件添加到归档文件本身

tar.add(file_path, arcname=os.path.relpath(file_path, backup_directory), recursive=False)

但是,似乎有一个故障保护机制,文件不会被添加。顺便说一句,你可以用检查当前存档中有什么

tar.getmembers()

在下一行中,您尝试获取文件的信息,但由于它没有添加到归档中,因此会出现KeyError

info = tar.getmember(os.path.relpath(file_path, backup_directory))

有多种方法可以修复它,例如,可以将它放在trycatch块中

with tarfile.open(backup_file, "w:gz") as tar:
    for root, dirs, files in os.walk(backup_directory):
        for file in files:
            file_path = os.path.join(root, file)
            tar.add(file_path, arcname=os.path.relpath(file_path, backup_directory), recursive=False)
            try:
                info = tar.getmember(os.path.relpath(file_path, backup_directory))
            except KeyError:
                # Log the error or do something else
            info.uid = os.stat(file_path).st_uid
            info.gid = os.stat(file_path).st_gid
            info.mode = os.stat(file_path).st_mode
    tar.close()

相关问题