2016-07-19 10 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)行を挿入しようとしました。

ファイルを閉じている可能性はありますか?この問題を引き起こしている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

Agh!もちろんあなたは正しい。これが発生した後に一時ファイルを再度開くことはできますか? – Kin3TiX

+0

@ Kin3TiX:通常、ファイルは閉じられるとすぐに削除されますが、 'NamedTemporaryFile'コンストラクタに' delete = False'を渡して、それを防ぐことができます。その後、その名前でファイルを再度開きます。これを行う場合は、ファイルの終了時にファイルを削除する責任があることに注意してください。 – user2357112

関連する問題