在读写文件内容之前,必须和文件建立某种连接或者通信, 这个过程叫做open
一个文件.
在GNU系统中,这种连接有两种表示形式:stream
和file descriptor
, stream
是基于file descriptor
的.
stream
stream
差不多就是加上缓冲的文件描述符,写到流的字符通常会累计,按块写入文件(减少系统调用),输入也是如此.
三种缓冲策略:
- 无缓冲,和文件描述符差不多
- 行缓冲,收到换行
\n
就写 - 全缓冲, 按块进行读写
新开的流通常都是全缓冲的,有一个例外:连接到交互式设备(比如terminal)的通常是行缓冲的
对流进行fflush
会将其缓冲的输入全部写入到文件,很多情况下这个操作也是会自动进行的.
使用setvbuf
可以在打开一个流之后(还没有进行其他操作)更改其缓冲策略.
使用setbuf
来更改一个文件的缓冲区(你来提供buffer)
file descriptor
使用fdopen
来在文件描述符至少打开流.
对于流,可以使用fileno
函数获得其对应的文件描述符.
以下讲stream
和file descriptor
称为channel
来自同一次文件打开操作的channel
共享文件位置.(fileno
,fdopen
,dup
,dup2
,fork
(会dup
父进程的文件描述符吧)).
对于不支持随机存取的文件(terminal
,pipe
).其上所有channel
总是自动连接的.对于支持随机存取的文件,追加方式打开的channel
自动连接(共享文件位置)
不在上述之列的channel
之间就是相互独立的了.
复用文件描述符
dup(old)
: 复用文件描述符old,返回dup出的新的文件描述符dup2(old,new)
: 讲文件描述符old
用于new
,(原来的new
描述符被关闭)
其实不是很清楚多个连接的文件描述符关闭其中一个的时候会发生什么,刚才试了下,这样标准输出还是可以的:
dup2(STDIN_FILENO,3);
close(STDOUT_FILENO);
dup2(3,STDOUT_FILENO);
这个标准输入和标准输出应该是特殊文件吧,有没有办法可以检查一下呢?fstat
测试了一下,是字符型的设备,应该就是终端设备了.
Terminating a process, or executing a new program in the process, destroys all the streams in the process. If descriptors linked to these streams persist in other processes, their file positions become undefined as a result. To prevent this, you must clean up the streams before destroying them.
这个undefined的结果只是针对stream
吗,文件描述符好像是无异的. 如果是这样的话. 是stream
的何种属性导致它会如此表现呢?..好像上面最后一句话说出来了, 在摧毁之前必须clean up stream,clean 就是没有缓冲的输出,缓冲在文件描述符是不存在的,所以不用考虑这个问题(我都不知道我在考虑什么…).为什么缓冲区不clean不出问题呢? 我猜可能是流和文件描述符文件位置更新的时间不同,可能流是在写(不管是否实际写入文件)之后就更新位置,而文件描述符总是在写入文件的时候更新吧妈的(我猜的).
不了解前面说的terminal和pipe类型的文件上打开的channel都是同步的这个说法, 明显其表现不是这样的啊,pipe文件一端是从头写,一端是从头读的啊,那应该就是这些文件读方式打开和写方式打开的时候表现为两个内容同步的文件吧,晕了,不就是同一个文件吗, 可能就只是想要强调这些特殊文件是不能修改之前写入的数据吧…~~
还有一个问题是,在重定向一个文件作为管道的输入的时候,具体是怎么样的呢?文件内容是真的"输入",还是在另一端读的时候按需"输入"呢?..一开始就错了,好像这个重定向文件作为管道输入这个说法有问题, 应该是,用管道的输入端(管道流入端)取代某个文件(比如标准输出)作为输出文件,将管道的输出端(管道流出端)取代某个文件(比如标准输入)作为输入文件.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fds[2];
if (-1 == pipe(fds)){
perror("pipe");
return 1;
}
dup2(fds[0],STDIN_FILENO);
dup2(fds[1],STDOUT_FILENO);
int c;
write(fds[1],"a",1);
while((c = getchar()) != EOF) {
putchar('a');
fflush(stdout);
// 刚开始用putchar忘了flush了,堵在getchar了,都准备好推翻前面的结论了妈的..
// 开始都没想怎么write就行了..
}
return 0;
}
自给自足…这个有什么用呢…我要干什么呢…