目录
一,FILE
二,缓冲区
三,重定向
系统调用dup2
一,FILE
- FILE结构体内部包括
- 变量_fileno,即对应的文件描述符下标fd;
- 应用层C语言提供的缓冲区数据;
- 其IO相关函数与系统调用接口对应,封装了系统调用接口,本质上是通过fd访问;
- 向普通文件写入是全缓冲,向屏幕文件写入是行缓冲;
//语言层次上
int main()
{
printf("stdin fd=%d\n",stdin->_fileno);
printf("stdout fd=%d\n",stdout->_fileno);
printf("stderr fd=%d\n",stderr->_fileno);
FILE* fp = fopen("log.txt", "r");
printf("log.txt fd=%d\n",fp->_fileno);
pclose(fp);
return 0;
}
[wz@192 Desktop]$ ./target
stdin fd=0
stdout fd=1
stderr fd=2
log.txt fd=3
//路径/usr/include/stdio.h
typedef struct _IO_FILE FILE;
//路径/usr/include/libio.h
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
二,缓冲区
int main()
{
//C语言
printf("hello printf\n");
fprintf(stdout, "hello fprintf\n");
fputs("hello fputs\n", stdout);
//system call
const char* msg = "hello write\n";
write(1, msg, strlen(msg));
fork();
return 0;
}
//向屏幕刷新策略为行缓冲
[wz@192 Desktop]$ ./target
hello printf
hello fprintf
hello fputs
hello write
//去掉\n,除了系统调用只打印一个,其他都打印两个;
[wz@192 Desktop]$ ./target
hello writehello printfhello fprintfhello fputshello printfhello fprintfhello fputs
//输出重定向后,刷新策略改为全缓冲
//除了系统调用只打印一个,其他都打印两个;
[wz@192 Desktop]$ ./target > log.txt
[wz@192 Desktop]$ cat log.txt
hello write
hello printf
hello fprintf
hello fputs
hello printf
hello fprintf
hello fputs
- 库函数均刷新了两次,系统调用只刷新了一次;
- 库函数会自带缓冲区,重定向到普通文件,刷新策略会从行缓冲改为全缓冲;没有指定刷新,就会在进程结束时统一刷新;fork时,父子数据会发生写实拷贝;
- 系统调用没有所谓的用户级缓冲区,但OS会通过内核级的缓冲区;
三,重定向
//关闭默认打开的1指向的文件,即stdout
//此时新创建的文件,fd将会是1
//本来printf应打印到显示器,此时应该写入到log.txt
int main()
{
close(1);
int fd = open("log.txt", O_WRONLY|O_CREAT, 0644);
printf("fd=%d\n",fd);
close(fd);
return 0;
}
//此时不仅没有打印到屏幕,也没有写入到log.txt
[wz@192 Desktop]$ ./target
[wz@192 Desktop]$ cat log.txt
[wz@192 Desktop]$
int main()
{
close(1);
int fd = open("log.txt", O_WRONLY|O_CREAT, 0644);
printf("fd=%d\n",fd);
fflush(stdout);
close(fd);
return 0;
}
//刷新到了log.txt文件
[wz@192 Desktop]$ ./target
[wz@192 Desktop]$ cat log.txt
log.txt fd=1
系统调用dup2
int main()
{
int fd = open("log.txt", O_WRONLY|O_CREAT, 0644);
if(fd<0){
perror("open");
}
dup2(fd,1);
const char* msg = "write dup2\n";
write(1, msg, strlen(msg));
close(fd);
return 0;
}
//重定向后,向log.txt文件写入了
[wz@192 Desktop]$ ./target
[wz@192 Desktop]$ cat log.txt
write dup2
int main()
{
int fd = open("log.txt", O_RDONLY);
if(fd<0){
perror("open");
}
dup2(fd,0);
char buf[1024];
ssize_t r_size = read(0, buf, sizeof(buf)-1);
if(r_size>0){
buf[s]=0;
printf("%s\n",buf);
}
close(fd);
return 0;
}
//重定向后,从文件读取数据
[wz@192 Desktop]$ ./target
wirte dup2