2016-07-19 71 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