Python脚本打包目录并GPG加密后,解密时Tar文件损坏求助
问题分析与解决方案
我看到你遇到的问题是目录打包加密后,解密得到的tar文件损坏。仔细排查了你的代码,发现两个关键问题导致了这个情况:
问题1:手动关闭tar对象导致文件结构不完整
在dataTar函数里,你在with块中手动调用了tar.close(),但with语句的核心作用就是自动管理资源——当块结束时,会自动调用tar对象的close()方法,这个方法会完成tar文件的收尾工作(比如写入结束标记)。手动提前调用close()后,with块再次执行关闭操作,会直接破坏tar文件的结构,导致文件损坏。
问题2:错误的tar文件打开模式
你使用了'w|'模式创建tar文件,这个模式是流式写入模式,适用于从管道或标准输入读取数据并写入tar的场景。而直接创建本地tar文件时,应该使用普通的'w'模式,这样tarfile模块会正确处理文件的写入和结构完整性。
修改后的代码
下面是修复后的关键部分,以及完整的修正版本:
修复dataTar函数
def dataTar(): if os.path.isfile(dataToEncrypt): return else: # 使用'w'模式替代'w|',并移除多余的tar.close() with tarfile.open(tarFile, 'w') as tar: tar.add(dataToEncrypt)
完整修正代码
#!/usr/bin/env python3 # Takes file in does symmetric encryption with the password you provide # then adds it to a running IPFS(ipfs.io) instance. # import os import argparse import gnupg import ipfsapi import tarfile # Parse command arguments parser = argparse.ArgumentParser(description='Encrypt file/directory and add it to IPFS') parser.add_argument('-i','--input', help='File.txt or Directory', required=True) parser.add_argument('-p','--password', help='Password to encrypt with', required=True) args = parser.parse_args() # 设置临时GPG目录,避免默认目录的权限问题 gpg = gnupg.GPG(homedir='/tmp/gpg_temp') gpg.encoding = 'utf-8' # Get dataToEncrypt full path dataToEncrypt = os.path.abspath(args.input) # Setup tar filename to end with .zip tarFile = f"{dataToEncrypt}.tar" # Setup encrypted filename to end with .gpg encryptedFile = f"{dataToEncrypt}.tar.gpg" # Tell module where IPFS instance is located api = ipfsapi.connect('127.0.0.1', 5001) def dataTar(): if os.path.isfile(dataToEncrypt): return else: # 使用普通写入模式'w',移除手动close with tarfile.open(tarFile, 'w') as tar: tar.add(dataToEncrypt) def encryptFile(): passphrase = args.password if os.path.isfile(dataToEncrypt): output_file = f"{dataToEncrypt}.gpg" with open(dataToEncrypt, 'rb') as f: status = gpg.encrypt( f, recipients=[], # 对称加密不需要收件人,留空即可 symmetric='AES256', passphrase=passphrase, armor=False, output=output_file ) else: with open(tarFile, 'rb') as f: status = gpg.encrypt( f, recipients=[], symmetric='AES256', passphrase=passphrase, armor=False, output=encryptedFile ) print('ok: ', status.ok) print('status: ', status.status) print('stderr: ', status.stderr) # 验证加密文件是否正常生成 if os.path.exists(encryptedFile) and os.path.getsize(encryptedFile) > 0: print(f"加密文件 {encryptedFile} 创建成功") else: print("加密文件创建失败") def ipfsFile(encryptedFile): # Add encrypted file to IPFS ipfsLoadedFile = api.add(encryptedFile, wrap_with_directory=True) # Return Hash of new IPFS File fullHash = ipfsLoadedFile[1] ipfsHash = fullHash['Hash'] return ipfsHash def delEncryptedFile(encryptedFile): try: os.remove(encryptedFile) # 同时清理临时tar文件 if os.path.exists(tarFile): os.remove(tarFile) except Exception as e: print(f"Error: 无法删除文件 - {e}") def main(): dataTar() encryptFile() # 取消注释以下两行启用IPFS上传和文件清理 # ipfs_hash = ipfsFile(encryptedFile) # print(f"File encrypted and added to IPFS with this hash: {ipfs_hash}") # delEncryptedFile(encryptedFile) if __name__ == "__main__": main()
额外优化说明
- GPG目录调整:把GPG的homedir改成了
/tmp/gpg_temp,避免使用用户默认的~/.gnupg可能遇到的权限问题,这个目录会自动创建(如果不存在)。 - 代码简化:删除了不必要的括号,使用f-string让字符串拼接更简洁易读。
- 加密参数规范:明确设置
recipients=[],符合gnupg库对称加密的调用规范(之前的encrypt=False参数是多余的,对称加密模式下会自动忽略收件人)。 - 临时文件清理:在
delEncryptedFile中增加了删除临时tar文件的逻辑,避免残留文件占用空间。
验证方法
修复后,你可以按以下步骤验证:
- 运行脚本加密目录:
python3 your_script.py -i /path/to/your/dir -p your_password - 解密生成的文件:
gpg -d /path/to/your/dir.tar.gpg > test.tar - 检查tar完整性:
tar tvf test.tar,如果能正常列出目录内容,说明修复成功。
内容的提问来源于stack exchange,提问作者Troy Wilson
相关产品推荐
相关产品推荐

