我正在编写一些Python代码,它是从Apache调用的CGI脚本。
代码所做的第一件事是(我相信)尝试使用以下命令关闭 stdin/stdout/stderr:
for fd in [0, 1, 2]:
try:
os.close(fd)
except Exception:
pass
通常这是有效的,但是如果它们没有打开,我会收到“python.exe 已停止工作”、“问题导致程序停止正常工作”错误消息(Win32 异常)。
几个问题:
我不确定,但我敢打赌
os.close()
只是操作系统 close()
系统调用的 python 包装器。 Python 文件对象为用户处理一些很酷的东西,比如数据的内部缓冲等等,这在调用其 close()
方法时会得到处理。
最终,操作系统的
close()
系统调用将在 File 对象的文件描述符上调用。因此,在某个时刻调用 sys.stdin.close()
相当于调用 os.close(sys.stdin.fileno())
根据文档,您可以多次调用文件上的
close()
方法,Python 不会关心。文件对象甚至提供一个属性 closed
来检查文件是否打开:
>>> import os
>>> f = open(os.devnull)
>>> f.close()
>>> f.close()
>>> f.close()
>>> f.close()
>>> f.close()
>>> print f.closed
True
如果可能的话,我建议调用 sys.FD 的
close()
方法,因为它更干净、更Pythonic。
fileobjects.c
):static PyObject *
file_close(PyFileObject *f)
{
PyObject *sts = close_the_file(f);
if (sts) {
PyMem_Free(f->f_setbuf);
f->f_setbuf = NULL;
}
return sts;
}
PyDoc_STRVAR(close_doc,
"close() -> None or (perhaps) an integer. Close the file.\n"
"\n"
"Sets data attribute .closed to True. A closed file cannot be used for\n"
"further I/O operations. close() may be called more than once without\n"
"error. Some kinds of file objects (for example, opened by popen())\n"
"may return an exit status upon closing.");
static PyObject *
close_the_file(PyFileObject *f)
{
int sts = 0;
int (*local_close)(FILE *);
FILE *local_fp = f->f_fp;
char *local_setbuf = f->f_setbuf;
if (local_fp != NULL) {
local_close = f->f_close; // get fs close() method
/* SOME CONCURRENCY STUFF HERE... */
f->f_fp = NULL;
if (local_close != NULL) {
f->f_setbuf = NULL;
Py_BEGIN_ALLOW_THREADS
errno = 0;
sts = (*local_close)(local_fp); // Call the close()
Py_END_ALLOW_THREADS
f->f_setbuf = local_setbuf;
if (sts == EOF)
return PyErr_SetFromErrno(PyExc_IOError);
if (sts != 0)
return PyInt_FromLong((long)sts);
}
}
Py_RETURN_NONE;
}
static PyObject *
fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode,
int (*close)(FILE *))
{
...
f->f_close = close;
...
}
posixmodule.c
):/* This file is also used for Windows NT/MS-Win and OS/2. In that case the
module actually calls itself 'nt' or 'os2', not 'posix', and a few
functions are either unimplemented or implemented differently. The source
assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent
of the compiler used. Different compilers define their own feature
test macro, e.g. '__BORLANDC__' or '_MSC_VER'. For OS/2, the compiler
independent macro PYOS_OS2 should be defined. On OS/2 the default
compiler is assumed to be IBMs VisualAge C++ (VACPP). PYCC_GCC is used
as the compiler specific macro for the EMX port of gcc to OS/2. */
PyDoc_STRVAR(posix_close__doc__,
"close(fd)\n\n\
Close a file descriptor (for low level IO).");
/*
The underscore at end of function name avoids a name clash with the libc
function posix_close.
*/
static PyObject *
posix_close_(PyObject *self, PyObject *args)
{
int fd, res;
if (!PyArg_ParseTuple(args, "i:close", &fd))
return NULL;
if (!_PyVerify_fd(fd))
return posix_error();
Py_BEGIN_ALLOW_THREADS
res = close(fd); // close the file descriptor fd
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error(); // AKA raise OSError()
Py_INCREF(Py_None);
return Py_None;
}
OSError
:static PyObject *
posix_error(void)
{
return PyErr_SetFromErrno(PyExc_OSError);
}
因此,如果在同一个文件描述符上调用两次,则调用
os.close(fd)
应该会引发 OSError 。调用 file.close()
最终会调用 fclose(FILE *f)
并将处理它被多次调用。
例如:
echo example | python3 -c 'import os, sys; sys.stdin.close(); print(os.read(0, 10))'
而
os.close(0)
则关闭底层文件描述符。
如果您不使用标准输入,最好关闭文件描述符,以便在其他程序写入时使错误显而易见。 (如果未使用 stdout 和 stderr,则类似。)