2016-07-19 5 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 : 일반적으로 파일은 닫히 자마자 삭제되지만,'NamedTemporaryFile' 생성자에'delete = False'를 전달하여이를 방지하고 그 이름으로 파일을 다시 열 수 있습니다. 이 작업을 수행하면 파일 작성이 완료되면 파일을 삭제할 책임이 있음을 기억하십시오. – user2357112

관련 문제