2016-07-19 22 views
1

我遇到了一个问题,在Python中写入NamedTemporaryFile然后再读回。该函数通过tftpy将文件下载到临时文件,读取它,散列内容,然后将散列摘要与原始文件进行比较。有问题的函数如下所示:Python NamedTemporaryFile - ValueError阅读时

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 

的问题是,每次我试图用ValueError - I/O Operation on a closed file执行线uploaded_digest = hashlib.sha256(tempfile.read()).hexdigest()的应用程序错误出时间。由于with块没有完成,我正在努力理解为什么临时文件将被关闭。我能想到的唯一可能是tftpy在下载完成后关闭了文件,但我无法在tftpy源文件中找到任何会发生这种情况的点。请注意,我也尝试插入行tempfile.seek(0)以便将文件恢复为正确的阅读状态,但这也给我ValueError

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

回答

2

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关闭文件。

+0

唉!当然你是对的。发生这种情况后,我可以重新打开临时文件吗? – Kin3TiX

+0

@ Kin3TiX:正常情况下,只要文件关闭,文件就会被删除,但是您可以将'delete = False'传递给'NamedTemporaryFile'构造函数来防止这种情况发生,然后通过名称重新打开文件。如果你这样做,请记住,当你完成它时,你将负责删除文件。 – user2357112