父子进程通过两个管道进行通信。

- 伪代码
- #include
- void client(int, int), server(int, int);
-
- int main(int argc, char** argv) {
- int pipe1[2], pipe2[2];
- pid_t childpid;
-
- Pipe(pipe1);
- Pipe(pipe2);
-
- if ((childpid == Fork()) == 0) {
- // child
- Close(pipe1[1]);
- Close(pipe2[0]);
-
- server(pipe1[0], pipe2[1]);
- exit(0);
- }
-
- // parent
- Close(pipe1[0]);
- Close(pipe2[1]);
- client(pipe2[0], pipe1[1]);
-
- Waitpid(childpid, NULL, 0);
- exit(0);
- }
open()函数
- int fd;
- fd = open("test.txt", O_RDONLY);
- if (fd == -1) {
- //错误
- }
-
- ==========================================
- int fd;
- //如果文件存在,则截断文件,文件不存在,则创建,并且后面指定了文件的权限
- fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
creat()函数
- #include
- #include
- #include
-
- int fd;
- fd = creat(file, 0644);
- if (fd == -1)
-
- 和
- fd = open(file, O_RWONLY | O_CREAT | O_TRUNC, 0644);
- 是一样的效果。
read()函数
- #include
- ssize_t read(int fd, void* buf, size_t len);
-
- 从文件描述符fd对应当前的位置读取len字节到buf中,执行成功返回读取的字节数,失败返回-1并设置errno,
-
- ssize_t ret;
- while(len != 0 && (ret = read(fd, buf, len)) != 0) {
- if (ret == -1) {
- if (errno == EINTR) continue;
- perror("read");
- break;
- }
- len -= ret;
- buf += ret;
- }
lseek()查找文件位置
- #include
- #include
-
- off_t lseek (int fd, off_t pos, int origin);
-
origin参数主要有一下值:
SEEK_CUR:fd的当前文件位置被设置为当前值+pos(其值可是负数,0,正数),pos为零时,返回当前位置。
SEEK_END:fd的当前位置被设定为文件的当前长度+pos(其值可是负数,0,正数),pos为零时,当前位置为文件的末端。
SEEK_SET:fd的当前位置被设置为pos,pos为零时,偏移值为文件的开头。
此调用执行成功时,返回新的文件位置,执行错误时,返回-1,并且将errno设置为适当值。
- //将文件fd的位置设置为1825
- ret = lseek(fd, (off_t)1825, SEEK_SET);
- if (ret == (off_t)-1)
-
- //将文件的位置设置为文件的末端
- ret = lseek(fd, 0, SEEK_END);
-
- //找到文件当前的位置
- ret = lseek(fd, 0, SEEK_CUR);
pread()和pwrite()函数
- #define _XOPEN_SOURCE 500
- #include
- ssize_t pread(int fd, void* buf, size_t count, off_t pos);
-
- 此调用会从文件fd的pos位置读取count字节放入到buf中
-
- ssize_t pwrite(int fd, const void*buf, size_t count, off_t pos);
-
- 将count字节从buf中写入到fd的文件pos位置
-
- 以上两个调用不会改变文件的位置
截短文件ftruncate(int fd, off_t len)和truncate(const char* path, off_t len);
- #include
- #include
- int ftruncate(int fd, off_t len);
-
- int truncate(const char* path, off_t len);
这两个系统调用会将指定的文件截短成len所指定的长度,不改变文件当前位置。
select()
- #include
- #include
- #include
- #include
-
- #define TIMEOUT 5 //select的等待时间,秒为单位
- #define BUF_LEN 1024 //读取缓冲区,字节为单位
- //编译: gcc -o select_test select_test.cpp
- int main(void) {
- struct timeval tv;
- fd_set readfds;
- int ret;
-
- // 等候stdin的输入数据
- FD_ZERO(&readfds);
- FD_SET(STDIN_FILENO, &readfds);
-
- // 等候5秒的时间
- tv.tv_sec = TIMEOUT;
- tv.tv_usec = 0;
-
- ret = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);
- if (ret == -1) {
- perror("select");
- return 1;
- } else if(!ret) {
- printf("%d seconds elapsed.\n", TIMEOUT);
- return 0;
- }
- // 是否可读
- if (FD_ISSET(STDIN_FILENO, &readfds)) {
- char buf[BUF_LEN+1];
- int len;
- // 保证不会遭到阻挡
- len = read(STDIN_FILENO, buf, BUF_LEN);
- if (len == -1) {
- perror("read");
- return 1;
- }
- if (len) {
- buf[len] = '\0';
- printf("read: %s\n", buf);
- }
- return 0;
- }
- fprintf(stderr, "This should not happen!\n");
- return 1;
- }
-
poll()函数
- #include
- #include
- #include
-
- #define TIMEOUT 5 //poll的等待时间
- /*
- 使用poll()同时检查由读取stdin以及写入stdout是否会受到阻挡
- */
-
- int main() {
- struct pollfd fds[2];
- int ret;
-
- // 查看stdin输入
- fds[0].fd = STDIN_FILENO;
- fds[0].events = POLLIN;
-
- // 查看stdout是否可供写入
- fds[1].fd = STDOUT_FILENO;
- fds[1].events = POLLOUT;
-
- ret = poll(fds, 2, TIMEOUT*1000);
- if (ret == -1) {
- perror("poll");
- return 1;
- }
- if (!ret) {
- printf("%d seconds elapsed.\n", TIMEOUT);
- return 0;
- }
- if (fds[0].revents & POLLIN) {
- printf("stdin is readable\n");
- }
- if (fds[1].revents & POLLOUT) {
- printf("stdout is writable\n");
- }
- return 0;
- }
运行上述程序
./poll
输出stdout is writable
添加一个输入,运行
./poll < xxxx.txt
stdin is readable
stdout is writable
fdopen()将一个已打开的文件描述符fd转成流
- #include
- FILE * fdopen(int fd, const char* mode);
关闭流
fclose()关闭流
- #include
- int fclose(FILE* stream);
关闭所有流
- #define _GNU_SOURCE
- #include
- int fcloseall(void);
一次读取一个字符
- #include
- //返回类型需是int类型
- int fgetc(FILE* stream);
将字符放回
- #include
- int ungetc(int c, FILE* stream);
读取一整行
- #include
- char* fgets(char* str, int size, FILE* stream);
- char* s;
- int c;
- s = str;
- while(--n>0 && (c = fgetc(stream)) != EOF) {
- *s++ = c;
- }
- *s = '\0';
遇到d时停止读取
- char* s;
- int c = 0;
- s = str;
- while(--n>0 && (c = fgetc(stream)) != EOF && (*s++ = c) != d);
- if (c == d)
- *--s = '\0';
- else
- *s = '\0';
读取二进制数据
- #include
- size_t fread(void* buf, size_t size, size_t nr, FILE* stream);
写入一个字符
- #include
- int fputc(int c, FILE* stream);
写入一个字符串
- #include
- int fputs(const char* str, FILE* stream)
fputs()会把str所指向的以null分割的字符串全部写入到stream流中,执行成功返回一个非负值,执行失败,返回EOF。
写入二进制数据
- #include
- size_t fwrite(void* buf, size_t size, size_t nr, FILE* stream);
- 执行成功返回写入的元素数目,而不是字节数,执行失败,返回一个小于nr的值,指发生了错误。
- #include
-
- int main() {
- FILE* in, *out;
- struct pirate {
- char name[100]; //姓名
- unsigned long booty;
- unsigned int beard_len;
- } p, blackbeard = {"Edward Teach", 950, 48};
-
- // 将blackbear写入一个流中,再读出来
- out = fopen("data", "w");
- if (!out) {
- perror("fopen");
- return 1;
- }
- if (!fwrite(&blackbeard, sizeof(struct pirate), 1, out)) {
- perror("fwrite");
- return 1;
- }
- if (fclose(out)) {
- perror("fclose");
- return 1;
- }
- in = fopen("data", "r");
- if (!in) {
- perror("fopen");
- return 1;
- }
- if (!fread(&p, sizeof(struct pirate), 1, in)) {
- perror("fread");
- return 1;
- }
- if (fclose(in)) {
- perror("fclose");
- return 1;
- }
- printf("name=\"%s\" booty=%lu beard_len = %u\n", p.name, p.booty, p.beard_len);
- return 0;
- }
查找流fseek()
- #include
- int fseek(FILE* stream, long offset, int whence);
如果whence的值被设置为SEEK_SET,则文件位置会被设置为offset,如果whence的值被设置为SEEK_CUR,则文件位置会被设置为当前位置加上offset,如果whence的值被设置为SEEK_END,则文件的位置会被设置为文件末端加上offset。
执行成功时返回0,清除EOF的指示器并取消ungetc()所造成的影响(如果有的话),发生错误返回-1,并将errno设置为适当值,
fsetpos()
- #include
- int fsetpos(FILE* stream, fpos_t *pos);
将流重新设置为开头
- #include
- void rewind(FILE* stream);
-
- //调用如下
- rewind(stream)
- 和下面的功能相同
- fseek(stream,0, SEEK_SET);
注意:rewind没有返回值,因此无法传达错误信息,如果要确认错误信息,需要调用之前先清除errno的值,在事后检查。
- errno = 0;
- rewind(stream);
- if (errno)
- //错误
获取当前位置
lseek()函数调用结束会返回当前位置,fseek()函数不会,要获得当前位置使用ftell()函数
- #include
- long ftell(TILE* stream);
发生错误返回-1,并且将errno设置为合适的值。
fgetpos()
- #include
- int fgetpos(FILE* stream, fpos_t *pos);
成功返回0,并且将位置保存在pos中。
刷新一个流
- #include
- int fflush(FILE* stream);
将流中的数据刷新至内核,如果stream为NULL,则进程中所有的流都会被刷新。
检查错误ferror()
- #include
- int ferror(FILE* stream);
用于检查流上是否有错误。
feof()用于检测stream上是否设置了EOF指示器。
- #include
- int feof(FILE* stream);
clearerr()用于清除stream之上的错误和EOF指示器。
- #include
- void clearerr(FILE* stream);
获得相应的文件描述符
- #include
- int fileno(FILE* stream);
设置缓冲模式
- #include
- int setvbuf(FILE* stream, char* buf, int mod, size_t size);
setvbuf()函数会将stream的缓冲区设置为mode类型,_IONBF:未经缓冲,_IOLBF:行缓冲,_IOFBF:经块缓冲。_IONBF(在此情况下会忽略buf和size)除外,buf会指向一个大小为size字节的缓冲区,而标准IO将以此为特定流的缓冲区,如果buf的值为NULL,则glibc会自动分配一个缓冲区。
打开流之后,必须setvbuf函数,而且必须在对流执行任何操作之前进行.