python 利用字节流文件实现文件加密并压缩
特别注意!!!
使用tkinterdnd2
后打包前需要在项目目录下添加以下文件hook-tkinterdnd2.py
,添加之后打包的代码需要加上后缀--additional-hooks-dir=.
详情见github作者描述
这个库的作者就是个大坑比!!!
file hook-tkinterdnd2.py
"""pyinstaller hook file. You need to use this hook-file if you are packaging a project using tkinterdnd2. Just put hook-tkinterdnd2.py in the same directory where you call pyinstaller and type: pyinstaller myproject/myproject.py --additional-hooks-dir=. """ from PyInstaller.utils.hooks import collect_data_files, eval_statement datas = collect_data_files('tkinterdnd2')
运行前需要先安装依赖:pycryptodome
其他的忘了😂
这是其他的依赖
压缩成一个文件1.0
from asyncio import streams import os import base64 import zipfile import time import tkinter.filedialog from fileinput import filename from tkinter import * from ttkbootstrap import * from ttkbootstrap.constants import * from turtle import color, width from importlib.resources import path from sqlite3 import Date from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex class FileAES: def __init__(self, key): self.key = key #将密钥转换为字符型数据 self.mode = AES.MODE_ECB #操作模式选择ECB self.unicode = 'utf-8' #默认字符集 self.compressPostfix = '.lambert' self.ui() def ui(self): theme = ['vapor', 'solar', 'pulse', 'minty'] style = Style(theme=theme[2]) win = style.master win.title("内部加密 / 解密工具包 1.0") # sw = win.winfo_screenwidth() # sh = win.winfo_screenheight() # ww = 272 # wh = 160 # x = (sw - ww) / 2 # y = (sh - wh) / 2 # win.geometry("%dx%d+%d+%d" % (ww, wh, x, y)) win.resizable(0, 0) self.file_names = [] self.folder_name = StringVar() self.folder_name.set("") self.text = Text(win, width=29, height=5, undo=True, autoseparators=False) self.text.configure(state='disabled') self.pack_name = Label(win, text="压缩后名称:") self.pack_name_value = Entry(win, width=14, textvariable=self.folder_name) self.btn = Button(win, text="选择文件", command=self.select_file, width=12) self.btn1 = Button(win, text="执行", command=self.handler_file, width=13, style=(INFO, OUTLINE)) self.text.grid(row=0, column=0, columnspan=4, rowspan=4) self.pack_name.grid(row=5, column=0, sticky="") self.pack_name_value.grid(row=5, column=1, sticky="") self.btn.grid(row=6, column=0, sticky="") self.btn1.grid(row=6, column=1, sticky="") win.mainloop() def add_to_16(self, text): if len(text.encode(self.unicode)) % 16: add = 16 - (len(text.encode(self.unicode)) % 16) else: add = 0 text = text + ('\0' * add) return text.encode(self.unicode) # 加密函数 def encrypt(self, text): key = keys.encode(self.unicode) mode = AES.MODE_ECB text = self.add_to_16(text) cryptos = AES.new(key, mode) cipher_text = cryptos.encrypt(text) return b2a_hex(cipher_text) # 解密函数 def decrypt(self, text): key = keys.encode(self.unicode) mode = AES.MODE_ECB cryptor = AES.new(key, mode) plain_text = cryptor.decrypt(a2b_hex(text)) return bytes.decode(plain_text).rstrip('\0') # 函数功能是zip_file_list所有文件,和zip_dir_list所有目录下的所有文件,被压缩到一个zip_file_name的压缩文件中 def my_zip_function(self, zip_file_name, zip_file_list=[], zip_dir_list=[]): # 压缩文件最后需要close,为了方便我们直接用with with zipfile.ZipFile(zip_file_name, "w") as zip_obj: # 压缩文件 for tmp_file in zip_file_list: with open(tmp_file, 'rb') as f: streams = f.read() zip_obj.writestr(os.path.split(tmp_file)[1], streams) # 压缩目录 for tmp_dir in zip_dir_list: # zipfile没有直接压缩目录的功能,要压缩目录只能遍历目录一个一个文件压。 for root, dirs, files in os.walk(tmp_dir): # 如果想要目录为空时仍将该目录压缩进去,该目录也要压缩一遍;反之请将以下行注释掉 zip_obj.write(root) for tmp_file in files: # 拼接文件完整目录,不然只用文件名代码找不到文件 tmp_file_path = os.path.join(root, tmp_file) zip_obj.write(tmp_file_path) # 函数功能是遍历压缩文件中的所有文件 def my_traversal_zip_function(self, zip_file_name): with zipfile.ZipFile(zip_file_name, "r") as zip_obj: all_file_list = zip_obj.infolist() # 函数的功能是将压缩文件直接解压 def my_unzip_function(self, zip_file_name, path="."): with zipfile.ZipFile(zip_file_name, "r") as zip_obj: zip_obj.extractall(path=path) # 选取文件 def select_file(self): self.file_names self.file_names.clear() # 清空列表 self.file_names += list( tkinter.filedialog.askopenfilenames(title="选取要操作的文件")) if len(self.file_names) != 0: self.text.configure(state='normal') # 打开锁 self.text.delete('1.0', END) string_filename = "" for i in range(0, len(self.file_names)): string_filename += str(self.file_names[i]) + "\n" self.text.insert(INSERT, "您选择的文件是:\n" + string_filename) self.text.configure(state='disabled') # 上锁 else: self.text.insert(INSERT, "您没有选择任何文件") # 加密或解密多个文件 def handler_file(self): if self.folder_name.get() == '': self.folder_name.set(time.strftime("%Y.%m.%d %H %M %S")) folder = [] self.zip_file_name = self.folder_name.get() + ".zip" self.zip_file_list = [] self.zip_dir_list = [] handler_type = '' for file_path in self.file_names: path = os.path.split(file_path)[0] # 路径 name = os.path.split(file_path)[1] # 文件名 if os.path.splitext(file_path)[1] == '.zip': handler_type = 'unpack' dirs = os.path.join(path, os.path.splitext(name)[0]) if not os.path.exists(dirs): os.mkdir(dirs) # os.makedirs(dirs) self.my_unzip_function(name, path=dirs) file_list = os.listdir(dirs) for dirs_file_name in file_list: dirs_file_path = os.path.join(dirs, dirs_file_name) with open(dirs_file_path, "rb") as f: stream = self.decrypt(f.read()) data = base64.b64decode(stream) name = os.path.splitext(dirs_file_name)[0] with open(os.path.join(dirs, name), "wb") as new_file: new_file.write(data) os.remove(dirs_file_path) elif os.path.splitext(file_path)[1] == self.compressPostfix: handler_type = 'deciphering' with open(file_path, "rb") as f: stream = self.decrypt(f.read()) data = base64.b64decode(stream) name = os.path.splitext(file_path)[0] with open(os.path.join(name, ""), "wb") as new_file: new_file.write(data) else: handler_type = 'pack' with open(file_path + self.compressPostfix, "wb") as new_file: with open(file_path, "rb") as f: stream = base64.b64encode(f.read()) data = self.encrypt(stream.decode(self.unicode)) new_file.write(data) # folder.append(os.path.split(file_path)[1] + self.compressPostfix) folder.append(file_path + self.compressPostfix) self.zip_file_list += folder self.zip_dir_list = [] if handler_type == 'pack': self.my_zip_function(self.zip_file_name, self.zip_file_list, self.zip_dir_list) # self.my_traversal_zip_function(self.zip_file_name) for file_path in self.file_names: os.remove(file_path + self.compressPostfix) # 删除加密后的中间文件 if __name__ == '__main__': keys = 'skldfjlkskjfslkj' # decode() 转字符串 encode() 转字节流 FileAES(keys)
压缩成多个文件 1.1
from asyncio import streams import os import base64 import zipfile import time import tkinter.filedialog import re import random from fileinput import filename from tkinter import * from ttkbootstrap import * from ttkbootstrap.constants import * from turtle import color, width from importlib.resources import path from sqlite3 import Date from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex # 这版 文件加密解密分块儿多组 class FileAES: def __init__(self): self.keys = '' # 将密钥转换为字符型数据,16、24或32位 self.mode = AES.MODE_ECB # 操作模式选择ECB self.unicode = 'utf-8' # 默认字符集 self.compressPostfix = '.skj' self.ui() def ui(self): theme = ['vapor', 'solar', 'pulse', 'minty'] style = Style(theme=theme[0]) win = style.master win.title("内部加密 / 解密工具包 1.1") # sw = win.winfo_screenwidth() # sh = win.winfo_screenheight() # ww = 350 # wh = 200 # x = (sw - ww) / 2 # y = (sh - wh) / 2 # win.geometry("%dx%d+%d+%d" % (ww, wh, x, y)) # win.resizable(0, 0) self.file_names = [] self.encrypt_string = StringVar() # 加密字符串 self.encrypt_string.set("skldfjlkskjfslkj") # 设置加密字符串初始值 self.folder_name = StringVar() self.folder_name.set("") self.encrypt_name = Label(win, text="密码: ") self.text = Text(win, width=35, height=5, undo=True, autoseparators=False) self.text.configure(state='disabled') self.pack_name = Label(win, text="压缩包名:") self.pack_name_value = Entry(win, textvariable=self.folder_name) self.encrypt_string_value = Entry(win, textvariable=self.encrypt_string) self.btn = Button(win, text="选择文件", command=self.select_file, width=12) self.btn1 = Button(win, text="执行", width=19, command=self.handler_file, style=(INFO, OUTLINE)) self.text.grid(row=0, column=0, columnspan=4, rowspan=4) # 显示文字区域 self.pack_name.grid(row=5, column=0, sticky="") # 压缩 tip self.pack_name_value.grid(row=5, column=1, sticky="") # 压缩 input self.encrypt_name.grid(row=6, column=0, sticky="") # 加密 tip self.encrypt_string_value.grid(row=6, column=1, sticky="") # 加密 input self.btn.grid(row=7, column=0, sticky="") # 按钮选择文件 self.btn1.grid(row=7, column=1, sticky="") # 执行·· win.mainloop() def add_to_16(self, text): if len(text.encode(self.unicode)) % 16: add = 16 - (len(text.encode(self.unicode)) % 16) else: add = 0 text = text + ('\0' * add) return text.encode(self.unicode) # 加密函数 def encrypt(self, text): key = self.keys.encode(self.unicode) mode = AES.MODE_ECB text = self.add_to_16(text) cryptos = AES.new(key, mode) cipher_text = cryptos.encrypt(text) return b2a_hex(cipher_text) # 解密函数 def decrypt(self, text): key = self.keys.encode(self.unicode) mode = AES.MODE_ECB cryptor = AES.new(key, mode) plain_text = cryptor.decrypt(a2b_hex(text)) return bytes.decode(plain_text).rstrip('\0') # 函数功能是zip_file_list所有文件,和zip_dir_list所有目录下的所有文件,被压缩到一个zip_file_name的压缩文件中 def my_zip_function(self, zip_file_name, zip_file_list=[], zip_dir_list=[]): # 压缩文件最后需要close,为了方便我们直接用with with zipfile.ZipFile(zip_file_name, "w") as zip_obj: # 压缩文件 for tmp_file in zip_file_list: with open(tmp_file, 'rb') as f: streams = f.read() zip_obj.writestr(os.path.split(tmp_file)[1], streams) # 压缩目录 for tmp_dir in zip_dir_list: # zipfile没有直接压缩目录的功能,要压缩目录只能遍历目录一个一个文件压。 for root, dirs, files in os.walk(tmp_dir): # 如果想要目录为空时仍将该目录压缩进去,该目录也要压缩一遍;反之请将以下行注释掉 zip_obj.write(root) for tmp_file in files: # 拼接文件完整目录,不然只用文件名代码找不到文件 tmp_file_path = os.path.join(root, tmp_file) zip_obj.write(tmp_file_path) # 函数功能是遍历压缩文件中的所有文件 def my_traversal_zip_function(self, zip_file_name): with zipfile.ZipFile(zip_file_name, "r") as zip_obj: all_file_list = zip_obj.infolist() # 函数的功能是将压缩文件直接解压 def my_unzip_function(self, zip_file_name, path): with zipfile.ZipFile(os.path.join(path, zip_file_name), "r") as zip_obj: zip_obj.extractall( os.path.join(path, os.path.splitext(zip_file_name)[0])) # 选取文件 def select_file(self): self.file_names self.file_names.clear() # 清空列表 self.file_names += list( tkinter.filedialog.askopenfilenames(title="选取要操作的文件")) if len(self.file_names) != 0: self.text.configure(state='normal') # 打开锁 self.text.delete('1.0', END) string_filename = "" for i in range(0, len(self.file_names)): string_filename += str(self.file_names[i]) + "\n" self.text.insert(INSERT, "您选择的文件是:\n" + string_filename) self.text.configure(state='disabled') # 上锁 else: self.text.insert(INSERT, "您没有选择任何文件") # 计算时间差是否大于一天,返回布尔值 def diffTimeGreaterThanOne(formerly): today = int(str(time.time()).split('.')[0]) day = (today - formerly) / (24 * 3600 * 1000) boolean = 1 if day > 1 else 0 return boolean # 解密文件 def deciphering_file(self, file_list, dirs): name = re.sub(r'.skj\d+$', '', file_list[0]) datas = "" for i in file_list: nameNow = re.sub(r'.skj\d+$', '', i) if name != nameNow: stream = self.decrypt(datas.encode('ascii')) data = base64.b64decode(stream) with open(os.path.join(dirs, name), "wb") as new_file: new_file.write(data) name = nameNow datas = "" with open(os.path.join(dirs, i), "rb") as f: datas += f.read().decode('ascii') os.remove(os.path.join(dirs, i)) # 删除中间文件 stream = self.decrypt(datas.encode('ascii')) data = base64.b64decode(stream) with open(os.path.join(dirs, name), "wb") as new_file: new_file.write(data) name = nameNow # 解密文件夹 def deciphering_folder(self, dirs_file_path, dirs_file_name, dirs): with open(dirs_file_path, "rb") as f: stream = self.decrypt(f.read()) data = base64.b64decode(stream) name = os.path.splitext(dirs_file_name)[0] with open(os.path.join(dirs, name), "wb") as new_file: new_file.write(data) # 加密文件 def encrypt_file(self, file_path): all_file = [] num = random.randint(3, 6) with open(file_path, "rb") as f: stream = base64.b64encode(f.read()) data = self.encrypt(stream.decode(self.unicode)) # 对 2 进制内容进行加密 dataArr = self.slice_arr(data, num) index = 1 for datas in dataArr: file_name = file_path + self.compressPostfix + str(index) all_file.append(file_name) with open(file_name, "wb") as new_file: new_file.write(datas) # 将加密后的内容写入文件内 index += 1 return all_file # 分割数组 def slice_arr(self, datas, num): arr = [] length = len(datas) if length == 0: return arr t = math.ceil(length / num) start = 0 end = 0 i = 0 while 1: end = start + t remainder = length - t * (i + 1) # 剩余 if remainder < t: break data = datas[start:end] if remainder >= t else datas[end:length] arr.append(data) start = end i += 1 return arr # 加密或解密多个文件(方式:先将对应文件分别加密,再将加密后的文件压缩进一个压缩包) # 对于一个文件分成多个文件加密的实现方式:1. 先将文件进行加密 2. 将加密后的密文分成数份,分别放入不同的文件 3. 将文件统一进行打包 def handler_file(self): # 把密码进行补全,得到16、24或32位 str = self.encrypt_string.get() length = len(str) # 超出32位自动截取前32位 self.keys = str.rjust( 16, '1') if length > 0 and length < 16 else str.rjust( 24, '1') if length > 16 and length < 24 else str.rjust( 32, '1') if length > 24 and length < 32 else str[0:32] if len(self.file_names) > 0: # 判断压缩名称是否为空,为空制时间戳为包名 if self.folder_name.get() == '': self.folder_name.set(time.strftime("%Y.%m.%d %H %M %S")) self.zip_file_name = self.folder_name.get() + ".zip" self.zip_file_list = [] self.zip_dir_list = [] handler_type = '' for file_path in self.file_names: folder = [] path = os.path.split(file_path)[0] # 路径 name = os.path.split(file_path)[1] # 文件名 if os.path.splitext(file_path)[1] == '.zip': handler_type = 'unpack' dirs = os.path.join(path, os.path.splitext(name)[0]) if not os.path.exists(dirs): os.mkdir(dirs) # os.makedirs(dirs) self.my_unzip_function(name, path) file_list = os.listdir(dirs) file_list.sort() # 对数据进行排序 正序 # for dirs_file_name in file_list: # dirs_file_path = os.path.join(dirs, dirs_file_name) # self.deciphering_folder(dirs_file_path, dirs_file_name, # dirs) self.deciphering_file(file_list, dirs) elif os.path.splitext(file_path)[1] == self.compressPostfix: handler_type = 'deciphering' # 解密 self.deciphering(file_path) else: handler_type = 'pack' all_file = self.encrypt_file(file_path) self.zip_file_list = os.path.join( os.path.split(file_path)[0], self.zip_file_name) # folder.append(os.path.split(file_path)[1] + self.compressPostfix) folder += all_file self.zip_file_list += folder self.zip_dir_list = [] if handler_type == 'pack': self.my_zip_function(self.zip_file_name, self.zip_file_list, self.zip_dir_list) # self.my_traversal_zip_function(self.zip_file_name) for i in self.zip_file_list: os.remove(i) # 删除加密后的中间文件 else: self.text.configure(state='normal') # 打开锁 self.text.delete('1.0', END) self.text.insert(INSERT, "您没有选择任何文件") self.text.configure(state='disabled') # 上锁 if __name__ == '__main__': # decode() 转字符串 encode() 转字节流 FileAES()
有什么不同见解可以在评论区共同讨论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!