如何让Python程序在Mac上向受密码保护的文件追加内容
解决PermissionError并实现密码保护的密码存储文件
先解决当前的PermissionError
你遇到的PermissionError通常是这几个原因:
- 当前运行程序的用户对
passwords.txt所在目录没有写入权限 - 文件被其他程序占用(比如文本编辑器打开着)
- 文件本身被设置为只读属性
快速解决方法:
- 检查文件所在目录的权限,确保当前用户有读写权限
- 关闭所有可能打开该文件的程序
- 或者直接指定一个你有权限的路径,比如用户文档目录(需导入
os模块):file_path = os.path.join(os.path.expanduser("~"), "Documents", "passwords.txt")
实现密码保护的文件存储
普通文本文件没法直接设置密码,必须通过加密存储来实现。下面用cryptography库实现基于密码的加密存储,步骤如下:
1. 安装依赖
pip install cryptography
2. 修改后的完整代码
import stdio import stdrandom import os from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.backends import default_backend import base64 def randChar(a): stdrandom.shuffle(a) return a[0] def randLetter(a): stdrandom.shuffle(a) return a[0] def u_randLetter(a): stdrandom.shuffle(a) y = a[0] return y.upper() def rand_num(): return stdrandom.uniformInt(0, 10) def get_fernet_key(password: str, salt: bytes = None): # 生成或使用已有盐值 if salt is None: salt = os.urandom(16) # 从密码派生密钥 kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, backend=default_backend() ) key = base64.urlsafe_b64encode(kdf.derive(password.encode())) return key, salt def load_encrypted_data(file_path: str, password: str): try: with open(file_path, "rb") as f: salt = f.read(16) encrypted_data = f.read() key, _ = get_fernet_key(password, salt) fernet = Fernet(key) return fernet.decrypt(encrypted_data).decode() except FileNotFoundError: # 文件不存在时返回空字符串 return "" except Exception: # 密码错误或文件损坏 stdio.writeln("密码错误或文件损坏!") exit(1) def save_encrypted_data(file_path: str, data: str, password: str): key, salt = get_fernet_key(password) fernet = Fernet(key) encrypted_data = fernet.encrypt(data.encode()) with open(file_path, "wb") as f: f.write(salt) f.write(encrypted_data) def main(): special_Char = ["!", "@", "#", "$", "%", "^", "&", "*", "-", "+"] alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] password = [] for i in range(4): password.append(randLetter(alphabet)) password.append(rand_num()) password.append(u_randLetter(alphabet)) password.append(randChar(special_Char)) stdrandom.shuffle(password) for j in range(len(password)): stdio.write(password[j]) stdio.writeln() stdio.writeln("Username:") username = stdio.readString() stdio.writeln("Website:") website = stdio.readString() # 提示输入文件密码 stdio.writeln("请输入文件密码:") file_password = stdio.readString() # 设置文件路径(可自行修改) file_path = os.path.join(os.path.expanduser("~"), "passwords_encrypted.txt") # 加载已有加密数据 existing_data = load_encrypted_data(file_path, file_password) # 准备新内容 new_entry = f"{username}\n{website}\n Password: " for j in range(len(password)): new_entry += str(password[j]) new_entry += "\n\n\n" # 合并并保存加密数据 save_encrypted_data(file_path, existing_data + new_entry, file_password) stdio.writeln("密码已成功保存!") if __name__ == '__main__': main()
代码说明
- 密钥派生:用PBKDF2HMAC从用户输入的密码生成加密密钥,避免直接使用密码作为密钥,提升安全性
- 加密存储:每次保存时先读取已有加密内容,解密后追加新条目,再重新加密保存
- 盐值处理:第一次创建文件时自动生成随机盐值,并存入文件开头,解密时读取该盐值派生密钥
- 错误处理:密码错误或文件损坏时会提示并退出
注意事项
- 务必牢记文件密码,丢失后无法恢复加密内容
- 第一次运行时输入的密码将作为后续访问的唯一密码
- 建议定期备份加密后的文件
内容的提问来源于stack exchange,提问作者Fab
相关产品推荐
相关产品推荐

