如果使用 lseek(),为什么文件描述符上的 read() 会失败?
Why read() on file descriptor fails if lseek() is used?
在下面的示例中,我们关闭默认 stderr
并通过 fdopen()
在临时文件上重新打开它,使用描述符 2
,这是 dup()
从临时文件描述符。然后我们write()
直接给这个描述符2
。我们可以安全地这样做,因为这是对文件的第一个写操作,因此它有空缓冲区。在此之后,我们fprintf()
到新的stderr
。然后我们关闭 stderr
(因此,它的关联描述符 2
会自动关闭)。原始描述符 fd
仍然有效。通过它,我们转到临时文件的开头,读取其内容并将它们打印到标准输出。但是输出是乱码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char buf[200];
int n;
char fname[] = "/tmp/tst-perror.XXXXXX";
fd = mkstemp (fname);
fclose (stderr);
dup2 (fd, 2);
stderr = fdopen (2, "w");
fd = fileno(stderr);
char *s = "this is a test\n";
n = write(fd, s, strlen(s));
fprintf(stderr, "multibyte string\n");
fclose (stderr);
// close(fd);
// fd = open(fname, O_RDONLY);
lseek (fd, 0, SEEK_SET);
n = read (fd, buf, sizeof (buf));
printf("%.*s", (int) n, buf);
close (fd);
return 0;
}
输出为:
$ ./a.out
����
如果我们取消注释 "close" 和 "open" 行并注释 "lseek" 行,输出如预期的那样:
$ ./a.out
this is a test
multibyte string
write()
没有缓冲,stderr
关闭时注销,所以
为什么在读取文件前不关闭文件输出是乱码?
不检查函数的 return 值。如果它在那里,您就会发现错误。
无论如何,问题是:
fd = fileno(stderr); // getting the fd from current stderr
fclose (stderr); // closing stderr
...
lseek (fd, 0, SEEK_SET); // seeking on fd which was already closed
在最后一次调用和后续调用中 fd
实际上是未定义的(或者更确切地说,它引用了关闭的文件描述符)。因此,对 fd
的任何操作都将失败 EBADF
(无效的文件描述符)。
显然,如果您再次包含 fd = open(...)
,fd
将生效并且代码将起作用。
在下面的示例中,我们关闭默认 stderr
并通过 fdopen()
在临时文件上重新打开它,使用描述符 2
,这是 dup()
从临时文件描述符。然后我们write()
直接给这个描述符2
。我们可以安全地这样做,因为这是对文件的第一个写操作,因此它有空缓冲区。在此之后,我们fprintf()
到新的stderr
。然后我们关闭 stderr
(因此,它的关联描述符 2
会自动关闭)。原始描述符 fd
仍然有效。通过它,我们转到临时文件的开头,读取其内容并将它们打印到标准输出。但是输出是乱码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char buf[200];
int n;
char fname[] = "/tmp/tst-perror.XXXXXX";
fd = mkstemp (fname);
fclose (stderr);
dup2 (fd, 2);
stderr = fdopen (2, "w");
fd = fileno(stderr);
char *s = "this is a test\n";
n = write(fd, s, strlen(s));
fprintf(stderr, "multibyte string\n");
fclose (stderr);
// close(fd);
// fd = open(fname, O_RDONLY);
lseek (fd, 0, SEEK_SET);
n = read (fd, buf, sizeof (buf));
printf("%.*s", (int) n, buf);
close (fd);
return 0;
}
输出为:
$ ./a.out
����
如果我们取消注释 "close" 和 "open" 行并注释 "lseek" 行,输出如预期的那样:
$ ./a.out
this is a test
multibyte string
write()
没有缓冲,stderr
关闭时注销,所以
为什么在读取文件前不关闭文件输出是乱码?
不检查函数的 return 值。如果它在那里,您就会发现错误。
无论如何,问题是:
fd = fileno(stderr); // getting the fd from current stderr
fclose (stderr); // closing stderr
...
lseek (fd, 0, SEEK_SET); // seeking on fd which was already closed
在最后一次调用和后续调用中 fd
实际上是未定义的(或者更确切地说,它引用了关闭的文件描述符)。因此,对 fd
的任何操作都将失败 EBADF
(无效的文件描述符)。
显然,如果您再次包含 fd = open(...)
,fd
将生效并且代码将起作用。