【问题标题】:Python NamedTemporaryFile - ValueError When ReadingPython NamedTemporaryFile - 读取时出现ValueError
【发布时间】:2016-07-19 17:56:51
【问题描述】:

我在用 Python 写入 NamedTemporaryFile 然后将其读回时遇到问题。该函数通过 tftpy 将文件下载到临时文件,读取它,对内容进行哈希处理,然后将哈希摘要与原始文件进行比较。有问题的函数如下:

def verify_upload(self, image, destination):
    # create a tftp client
    client = TftpClient(ip, 69, localip=self.binding_ip)
    # generate a temp file to hold the download info
    if not os.path.exists("temp"):
        os.makedirs("temp")
    with NamedTemporaryFile(dir="temp") as tempfile, open(image, 'r') as original:
        try:
            # attempt to download the target image
            client.download(destination, tempfile, timeout=self.download_timeout)
        except TftpTimeout:
            raise RuntimeError("Could not download {0} from {1} for verification".format(destination, self.target_ip))
        # hash the original file and the downloaded version
        original_digest = hashlib.sha256(original.read()).hexdigest()
        uploaded_digest = hashlib.sha256(tempfile.read()).hexdigest()
        if self.verbose:
            print "Original SHA-256: {0}\nUploaded SHA-256: {1}".format(original_digest, uploaded_digest)
        # return the hash comparison
        return original_digest == uploaded_digest

问题是每次我尝试执行uploaded_digest = hashlib.sha256(tempfile.read()).hexdigest() 行时,应用程序都会出错,并显示ValueError - I/O Operation on a closed file。由于with 块不完整,我很难理解为什么临时文件会被关闭。我能想到的唯一可能性是 tftpy 在下载后正在关闭文件,但我在 tftpy 源代码中找不到任何会发生这种情况的点。请注意,我还尝试插入行 tempfile.seek(0) 以使文件恢复到正确的读取状态,但这也给了我ValueError

tftpy 是否可能关闭文件?我读到 NamedTemporaryFile 中可能存在导致此问题的错误?为什么在with 块定义的引用超出范围之前关闭文件?

【问题讨论】:

    标签: python temporary-files tftp hashlib


    【解决方案1】:

    TFTPy 正在关闭文件。在查看源代码时,您错过了以下代码路径:

    class TftpClient(TftpSession):
        ...
        def download(self, filename, output, packethook=None, timeout=SOCK_TIMEOUT):
            ...
            self.context = TftpContextClientDownload(self.host,
                                                     self.iport,
                                                     filename,
                                                     output,
                                                     self.options,
                                                     packethook,
                                                     timeout,
                                                     localip = self.localip)
            self.context.start()
            # Download happens here
            self.context.end()  # <--
    

    TftpClient.download 致电TftpContextClientDownload.end

    class TftpContextClientDownload(TftpContext):
        ...
        def end(self):
            """Finish up the context."""
            TftpContext.end(self)  # <--
            self.metrics.end_time = time.time()
            log.debug("Set metrics.end_time to %s", self.metrics.end_time)
            self.metrics.compute()
    

    TftpContextClientDownload.end 致电TftpContext.end

    class TftpContext(object):
        ...
        def end(self):
            """Perform session cleanup, since the end method should always be
            called explicitely by the calling code, this works better than the
            destructor."""
            log.debug("in TftpContext.end")
            self.sock.close()
            if self.fileobj is not None and not self.fileobj.closed:
                log.debug("self.fileobj is open - closing")
                self.fileobj.close()  # <--
    

    然后TftpContext.end 关闭文件。

    【讨论】:

    • 啊!你当然是对的。发生这种情况后我可以重新打开临时文件吗?
    • @Kin3TiX:通常,文件一关闭就会被删除,但您可以将delete=False 传递给NamedTemporaryFile 构造函数以防止这种情况发生,然后按文件名重新打开文件.如果您这样做,请记住,您将负责在完成文件后删除该文件。
    猜你喜欢
    • 1970-01-01
    • 2021-05-09
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2019-06-03
    • 1970-01-01
    • 2020-06-22
    相关资源
    最近更新 更多