2017年4月22日 星期六

[Python 文章收集] Using tempfile.mkstemp correctly

Source From Here
Preface
The mkstemp function in the tempfile module returns a tuple of 2 values:
* An OS-level handle to an open file (as would be returned by os.open())
* The absolute pathname of that file.

I often see code using mkstemp only to get the filename to the temporary file, following a pattern such as:
  1. from tempfile import mkstemp  
  2. import os  
  3.   
  4. def need_temp_storage():  
  5.     _, temp_path = mkstemp()  
  6.     os.system('some_commande --output %s' % temp_path)  
  7.     file = open(temp_path, 'r')  
  8.     data = file.read()  
  9.     file.close()  
  10.     os.remove(temp_path)  
  11.     return data  
This seems to be working fine, but there is a bug hiding in there. The bug will show up on Linux if you call this functions many time in a long running process, and on the first call on Windows. We have leaked a file descriptor.

How-To
The first element of the tuple returned by mkstemp is typically an integer used to refer to a file by the OS. In Python, not closing a file is usually no big deal because the garbage collector will ultimately close the file for you, but here we are not dealing with file objects, but with OS-level handles. The interpreter sees an integer and has no way of knowing that the integer is connected to a file. On Linux, calling the above function repeatedly will eventually exhaust the available file descriptors. The program will stop with:
IOError: [Errno 24] Too many open files: '/tmp/tmpJ6g4Ke'

On Windows, it is not possible to remove a file which is still opened by another process, and you will get:
Windows Error [Error 32]

Fixing the above function requires closing the file descriptor using os.close():
  1. from tempfile import mkstemp  
  2. import os  
  3.   
  4. def need_temp_storage():  
  5.     fd, temp_path = mkstemp()  
  6.     os.system('some_commande --output %s' % temp_path)  
  7.     file = open(temp_path, 'r')  
  8.     data = file.read()  
  9.     file.close()  
  10.     os.close(fd)  
  11.     os.remove(temp_path)  
  12.     return data  
If you need your process to write directly in the temporary file, you don't need to call os.write(fddata). The function os.fdopen(fd) will return a Python file object using the same file descriptor. Closing that file object will close the OS-level file descriptor. Below is a simple example:
>>> from tempfile import mkstemp
>>> fd, temp_path = mkstemp()
>>> import os
>>> fh = os.fdopen(fd, 'w')
>>> print("Write message to %s" % (temp_path))
Write message to /tmp/tmpjdbax_95
>>> fh.write('This is for testing')
19
>>> fh.close()
>>> os.system('cat %s' % (temp_path)) // The appending 0 is the return code
This is for testing0


沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...