所以,我正在阅读关于Linux中的文件I / O并想到了解决它。但是,我在代码中遇到了两个奇怪的行为,我正在努力找出它们的原因。
/*
* This program shows the usage of dup and dup2 functions
*/
#include "creep.h"
#include <fcntl.h>
#define BUFSIZE 2048
int main(int argc, char *argv[]) {
int fd, dup_fd, n;
char buf[BUFSIZE], buff[BUFSIZE];
if (argc != 2)
err_quit("Usage: dup <filename>\n");
fd = open(argv[1], O_RDWR);
while ((n = read(fd, buf, BUFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
dup_fd = dup(fd);
while ((n = read(dup_fd, buff, BUFSIZE)) > 0)
if (write(STDOUT_FILENO, buff, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
printf("\nValues are : %d and %d\n", fd, dup_fd);
close(fd);
exit(0);
}
现在,当我运行这个程序时: -
# ./dup dup.c
它实际上只打印一次文件而不是第二个重复描述符。
我为上述事情做了一个strace,希望能找到正在发生的事情,但我能看到的就是这个 - &gt;
open("dup.c", O_RDWR) = 3
read(3, "/*\n * This program shows the usa"..., 2048) = 708
write(1, "/*\n * This program shows the usa"..., 708/
------------omitting the file from trace-------------
read(3, "", 2048) = 0
dup(3) = 4
read(4, "", 2048) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f170112d000
write(1, "\n", 1
) = 1
write(1, "Values are : 3 and 4\n", 21Values are : 3 and 4
) = 21
close(3)
有点奇怪,第一次在fd
上进行读/写调用时,它们在缓冲区中有文件内容。但是对于dup_fd
,缓冲区为空。我很无能为什么会发生这种情况。以前,我两次使用相同的缓冲区,我认为我应该使用单独的缓冲区,但无济于事。
我读到dup
函数给出了编号最小的可用文件描述符,它与原始文件描述符重复。在Process Table Entry中的文件指针指向文件描述符的同一文件表的意义上重复。
为什么我无法使用重复的文件描述符读取文件。有什么我做错了吗?
creep.h
头文件: -
/*
* My own header, to be included before all standard system headers written by me.
*/
#ifndef _CREEP_H
#define _CREEP_H
#define _POSIX_C_SOURCE 200809L
#if defined(SOLARIS)
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 700
#endif
#include <sys/types.h> /* some systems will require this */
#include <sys/stat.h>
#include <sys/termios.h> /* for winsize */
#if defined(MACOS) || !defined(TIOCGWINSZ)
#include <sys/ioctl.h>
#endif
#include <stdio.h> /* for convenience */
#include <stdlib.h> /* for convenience */
#include <stddef.h> /* for offsetof */
#include <string.h> /* for convenience */
#include <unistd.h> /* for convenience */
#include <signal.h> /* for SIG_ERR */
#include <errno.h> /* for definition of errno */
#include <stdarg.h> /* ISO C variable arguments */
#include <syslog.h> /* for convenience */
#define MAXLINE 4096 /* max line length */
/*
* Default file access permissions for new files.
*/
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/*
* Default permissions for new directories.
*/
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | SIXOTH)
typedef void Sigfunc(int); /* for signal handlers */
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/*
* Prototypes for my own functions.
*/
char *path_alloc(size_t *);
long open_max(void);
int set_cloexec(int);
void clr_fl(int, int);
void set_fl(int, int);
void pr_exit(int);
void pr_mask(const char *);
Sigfunc *signal_intr(int, Sigfunc *);
void daemonize(const char *);
void sleep_us(unsigned int);
ssize_t readn(int, void *, size_t);
ssize_t writen(int, const void *, size_t);
int fd_pipe(int *);
int recv_fd(int, ssize_t (*func) (int, const void *, size_t));
int send_fd(int, int);
int send_err(int, int, const char *);
int serv_listen(const char *);
int serv_accept(int, uid_t *);
int cli_conn(const char *);
int buf_args(char *, int (*func)(int, char **));
int tty_cbreak(int);
int tty_raw(int);
int tty_reset(int);
void tty_atexit(void);
struct termios *tty_termios(void);
int ptym_open(char *, int);
int ptys_open(char *);
#ifdef TIOCGWINSZ
pid_t pty_fork(int *, char *, int, const struct termios *, const struct winsize *);
#endif
int lock_reg(int, int, int, off_t, int, off_t);
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lcok(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
pid_t lock_test(int, int, off_t, int, off_t);
#define is_read_lockable(fd, offset, whence, len) \
(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \
(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)
void err_msg(const char *, ...);
void err_dump(const char *, ...) __attribute__((noreturn));
void err_quit(const char *, ...) __attribute__((noreturn));
void err_cont(int, const char *, ...);
void err_exit(int, const char *, ...) __attribute__((noreturn));
void err_ret(const char *, ...);
void err_sys(const char *, ...) __attribute__((noreturn));
void log_msg(const char *, ...);
void log_open(const char *, int, int);
void log_quit(const char *, ...) __attribute__((noreturn));
void log_ret(const char *, ...);
void log_sys(const char *, ...) __attribute__((noreturn));
void log_exit(int, const char *, ...) __attribute__((noreturn));
void TELL_WAIT(void);
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);
/*
* ERROR Function Definitions
*/
static void err_doit(int, int, const char *, va_list);
/*
* Nonfatal error rleated to a system call.
* Print a message and return.
*/
void err_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
}
/*
* Fata error related to a system call.
* Print a message and terminate.
*/
void err_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Nonfatal error unrealted to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void err_cont(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void err_exit(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Fatal error related to a system call.
* Print a message, dump core and terminate.
*/
void err_dump(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(1); /* shouldn't get here */
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void err_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
}
/*
* Fatale error unrelated to a system call.
* Print a message and terminate.
*/
void err_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap) {
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error));
strcat(buf, "\n");
fflush(stdout);
fputs(buf, stderr);
fflush(NULL);
}
#if 0
/*
* ERROR Routines for programs that can run as a Daemon.
* Commented out because of undefined reference of log_to_stderr.
*/
static void log_doit(int, int, int, const char *, va_list ap);
/*
* Caller must define and set this: nonzero if
* interactive, zero if daemon
*/
extern int log_to_stderr;
/*
* Initialize syslog(), if running as daemon.
*/
void log_open(const char *ident, int option, int facility) {
if (log_to_stderr == 0)
openlog(ident, option, facility);
}
/*
* Nonfatal error rleated to a system call.
* Print a message with the systems' errno value and return.
*/
void log_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
}
/*
* Fata error related to a system call.
* Print a message and terminate.
*/
void log_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void log_exit(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, error, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void log_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
}
/*
* Fatale error unrelated to a system call.
* Print a message and terminate.
*/
void log_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void log_doit(int errnoflag, int error, int priority, const char *fmt, va_list ap) {
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error));
strcat(buf, "\n");
if (log_to_stderr) {
fflush(stdout);
fputs(buf, stderr);
fflush(stderr);
} else {
syslog(priority, "%s", buf);
}
}
#endif
#endif /* _CREEP_H */
答案 0 :(得分:2)
当你到达dup
时,你的第一个循环已经结束。
为什么结束?因为你读了一切。 fd
位于文件的末尾。
然后你复制它。现在您有2 fd
个引用相同的文件对象(&#34;打开文件描述&#34;在POSIX术语中)。他们在文件末尾 。
您需要快退(lseek(dup_fd, 0, SEEK_SET)
)才能再次阅读该文件。请注意,seek是对文件对象的操作,因此它会影响fd
。您可以fd
寻找0位置,然后从dup_fd
读取,然后再次阅读内容。
您甚至可以在调用read(fd,...)
和read(dup_fd,...)
之间切换,如果您只是在阅读时打印每个块,您仍然可以按顺序获取文件内容。
答案 1 :(得分:2)
这是预期的行为。 The POSIX documentation for dup()
州:
dup()
函数提供服务的备用接口 由fcntl()
使用F_DUPFD
命令提供。电话dup(fildes)
应相当于:fcntl(fildes, F_DUPFD, 0);
F_DUPFD
返回一个新的文件描述符,该描述符应如下所述进行分配 File Descriptor Allocation,但它应该是最低的 编号的可用文件描述符大于或等于第三个 参数
arg
,取为int
类型的整数。 新文件 描述符应引用与...相同的打开文件描述 原始文件描述符,并将共享任何锁。FD_CLOEXEC
与新文件描述符关联的标志应被清除以保留 该文件在调用其中一个exec函数时打开。
请注意粗体部分:&#34;相同的打开文件说明&#34;。
这意味着dup()
文件描述符与它dup()
的共享文件描述符的当前文件偏移量相同。
您已经通过读取文件中的所有数据将该偏移量设置到文件的末尾。