问题描述
我正在尝试使用cryptography
模块对文件进行加密,因此我不必缓冲可能占用大量内存的文件密文,然后我将不得不用已加密的文件替换原始文件.so我的解决方案是加密一块明文,然后尝试一次用16个字节的密文替换它(AES-CTR模式)。问题似乎是循环是无限循环。
pointer = 0
with open(path,"r+b") as file:
print("...ENCRYPTING")
while file:
file_data = file.read(16)
pointer += 16
ciphertext = aes_enc.update(file_data)
file.seek(pointer-16)
file.write(ciphertext)
print("...Complete...")
解决方法
- 那么如何解决这个问题。
正如西里尔·乔夫(Cyril Jouve)所述,请检查如果不是file_data
- 您还建议其他什么方法。
- 下面使用这种方法的副作用是什么。
以16字节为块的读取速度相对较慢。我想您有足够的内存来读取较大的块,例如4096、8192 ...
除非您有非常大的文件和有限的磁盘空间,否则我认为读取和写入同一文件没有任何好处。如果发生错误,并且如果os已经将数据写入磁盘,则您将丢失原始数据,并且将拥有不完整的加密文件,而您不知道该文件的哪个部分被加密。
创建一个新的加密文件,然后在没有错误的情况下将其删除并重命名,将更加容易和节省。
仅在一切正常的情况下,加密到新文件,捕获异常,检查加密文件的存在和大小,删除源并重命名加密文件。
import os
path = r'D:\test.dat'
input_path = path
encrypt_path = path + '_encrypt'
try:
with open(input_path,"rb") as input_file:
with open(encrypt_path,"wb") as encrypt_file:
print("...ENCRYPTING")
while True:
file_data = input_file.read(4096)
if not file_data:
break
ciphertext = aes_enc.update(file_data)
encrypt_file.write(ciphertext)
print("...Complete...")
if os.path.exists(encrypt_path):
if os.path.getsize(input_path) == os.path.getsize(encrypt_path):
print(f'Deleting {input_path}')
os.remove(input_path)
print(f'Renaming {encrypt_path} to {input_path}')
os.rename(encrypt_path,input_path)
except Exception as e:
print(f'EXCEPTION: {str(e)}')
,
文件对象没有“真实性”,因此您不能将其用作循环的条件。
当read()返回一个空字节对象(https://docs.python.org/3/library/io.html#io.BufferedIOBase.read)时文件位于EOF
with open(path,"r+b") as file:
print("...ENCRYPTING")
while True:
file_data = file.read(16)
if not file_data:
break
ciphertext = aes_enc.update(file_data)
file.seek(-len(file_data),os.SEEK_CUR)
file.write(ciphertext)
print("...Complete...")