如何使用pyminizip在Python 3.x中创建临时ZIP文件?

3

我需要创建一个临时ZIP文件来存储文件。该ZIP文件需要加密,因此zipfile 在这里行不通。该文件将进一步加密(ZIP将再次加密成另一个文件),因此压缩文件可用作减小其大小以进行更快的互联网传输以及第一层加密的方式。 以下是我目前所拥有的:

import getpass
import tempfile
import pyminizip

def ZipFunction():
    #This zips the file and encrypts it with a password
    filename = input('Enter the file name: ')
    passkey = getpass.getpass(prompt='Enter the password for the file: ')
    passkey2 = getpass.getpass(prompt='Confirm the password: ')
    if passkey != passkey2:
        print('The passwords must be the same! Please restart the process.')
        exit()
    else:
        #Here's where I need help
        with tempfile.TemporaryFile() as tmp:
            with pyminizip.compress(filename,None,tmp,passkey,9) as archive:
                zipstring = archive.readlines()

        #From here on the zipstring var is encrypted and creates the "further encrypted"
        #file. From here on the script works normally

返回的错误是ValueError: expected arguments are compress(src, srcpath, dst, pass, level)。 我愿意将pyminizip更换为另一种可以创建加密zip文件的工具。这个“双重加密层”是客户的需求,虽然我并不认为它是必要的,但我没有权力从项目中删除它。 我不习惯处理临时文件。我在这里做错了什么?


有一件看起来可疑的事情是你将 None 作为 srcpath 传递。 - martineau
谢谢Martineau!虽然这看起来很奇怪,但在此上下文之外使用相同的行会创建一个完全功能的zip文件。我尝试将“None”更改为“os.getcwd()”,但无济于事。 - The_Shatner
1个回答

1
使用tempfile模块可以创建临时文件,当关闭或离开with块时会自动删除。使用pyminizip模块可以获得加密的zip文件。 pyminizip.compress函数需要第三个参数指定生成的zip文件路径。如果文件已经存在,则尝试覆盖它。当前代码使用了对tempfile的引用(tmp),导致出现了观察到的错误消息:
ValueError: expected arguments are compress(src, srcpath, dst, pass, level) 

错误的直接原因是使用了引用本身而不是它的文件名,即为避免错误,应该实际使用tmp.name而不是tmp。然而,如果更改这个,会生成一个不同的错误消息,即
OSError: error in closing <path to temo file> (-102)                                    

这是因为pyminizip模块在临时文件仍处于打开状态时尝试删除它。如果在此之前关闭临时文件,它将被无错误消息覆盖。但是,这只会创建一个普通文件而不是临时文件,即当关闭或离开with块时该文件不会被自动删除。
因此,使用tempfile和pyminizip模块以这种方式创建临时加密zip文件是不可能的。然而,tempfile模块允许创建临时文件以及临时目录。与临时文件一样,离开with块时会删除临时目录。如果删除了临时目录,则其中包含的文件也会被删除。因此,一种替代方案是常规的加密zip文件(使用pyminizip模块创建),存储在临时文件夹中(使用tempfile模块创建)。
...
with tempfile.TemporaryDirectory() as tdir:
    sourceFile = <path to file to be zipped>
    destinationFile = "destFile.zip"
    password = "whatever"
    compression_level = 9 # 1-9
    pyminizip.compress(sourceFile, None, tdir + "\\" + destinationFile, password, compression_level)

    # inside with-block: temp-directory and contained encrypted zip-files exist
    ...                     

# outside with-block: temp-directory and contained encrypted zip-files deleted
...                     

如果离开with块,临时目录将被删除,以及其中包含的任何加密zip文件。
顺便说一下:pyminizip.compress不支持with语句。这会导致错误消息:AttributeError: __enter__。在当前代码中,您看不到此错误消息,因为发布的错误消息是在触发之前触发的。

这听起来很不错,但每当我尝试引用destinationFile时,它就会返回一个错误FileNotFoundError: [Errno 2] No such file or directory: 'destFile.zip'。我尝试了另一种方法 - zipfile = pyminizip.compress(sourceFile, None, tdir + "\\" + destinationFile, password, compression_level),但每当我尝试从_zipfile_变量中获取任何数据时,它就会返回None。有什么想法可以让我像上面的“原始”代码一样将创建的zip文件读取为字符串吗? - The_Shatner
1
(1) 必须在 with 块内访问 zip 文件,否则目录及其内容将已被删除。我在这里粘贴了我的测试程序。您必须更改源文件的路径 (sourceFile = "C:/Test/src.txt")。生成的 zip 文件将在 with 块内成功访问,在离开 with 块后访问将失败。这在我的机器上可以运行。 (2) 方法 zipfile = pyminizip.compress(... 必定会失败,因为 compress 总是返回 None - Topaco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接