目录
- fseek
- ftell
- rewind
- fflush
- getline
橙色
当你在文件中写入了10个字符后,又想把这10个字符读出来,该怎么做呢?因为有文件操作符指针的存在,此时该指针已经指在了这10个字符末尾,所以需要把该指针重定向,这就用了本文中所介绍的几个函数
fseek
int fseek(FILE *stream, long int offset, int whence)
- stream — 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
- offset — 这是相对 whence 的偏移量,以字节为单位。
- whence — 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
- 如果成功,则该函数返回零,否则返回非零值。
ftell
long int ftell(FILE *stream)
stream — 这是指向 FILE 对象的指针,该 FILE 对象标识了流。- 该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。
程序实例——求程序的有效字节
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv){ FILE *fp; if(argc < 2) { fprintf(stderr, "Usage... "); exit(1); } fp = fopen(argv[1], "r"); if(fp == NULL) { perror("fopen()"); exit(1); } // 将指针定位在文件末尾 fseek(fp, 0, SEEK_END); printf("%d ", ftell(fp)); exit(0); }
rewind
void rewind(FILE *stream)
相当于
注意:
fflush
int fflush(FILE *stream)
- 如果参数为
NULL (即没传递参数),则刷新所有的已打开的流 - 如果成功,该函数返回零值。如果发生错误,则返回 EOF,且设置错误标识符(即 feof)。
代码示例
#include <stdio.h> int main() { printf("Before while(1)"); while(1); printf("After while(1)"); exit(0); }
打印结果:
// 什么都不打印
原因:
对于标准输出,输出缓冲区刷新的时机:
- 输出缓冲区满
- 或者遇到换行符
- 强制刷新,或者进程结束
因此,可以修改为:
#include <stdio.h> #include <stdlib.h> int main() { // 遇到 刷新 printf("Before while(1) "); while(1); printf("After while(1) "); exit(0); }
或者修改为:
#include <stdio.h> #include <stdlib.h> int main() { printf("Before while(1)"); // 强制刷新 fflush(stdout); // 或者 fflush(NULL); while(1); printf("After while(1)"); exit(0); }
缓冲区的作用:大多数情况下是好事,合并系统调用,增加程序的吞吐量。
缓冲的分类:
- 行缓冲
line buffered :针对标准输出(终端设备),有换行刷新,缓冲满刷新,强制刷新三种,后两个和全缓冲一致; - 全缓冲
fully buffered :默认缓冲机制(除标准输出【终端设备】,例如重定向到文件),有缓冲满刷新,强制刷新两种,强制刷新例如调用fflush函数,或者进程结束时也会强制刷新;此时换行符仅仅只是个换行符,没有刷新功能; - 无缓冲
unbuffered :例如stderr ,需要立即输出,数据会立即读入内存或者输出到外存文件和设备上;
int setvbuf(FILE *stream, char *buffer, int mode, size_t size)
- stream — 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
- buffer — 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
- mode — 这指定了文件缓冲的模式:
getline
之前介绍的函数,都不能获得完整的一整行(有缓冲区大小的限制),而下面介绍的
- 到文件结束
- 遇到函数的定界符
- 输入达到最大限度
函数原型:
#include <stdio.h> ssize_t getline(char **lineptr, size_t *n, FILE *stream);
- lineptr:指向存放该行字符的指针,如果是NULL,则有系统帮助malloc,请在使用完成后free释放。该参数是一个二级指针,因此传参需要一级指针的地址。即函数会把读取到的字符串的首地址存放在一级指针中。
// 传参: char *ptr; // 函数内的实际操作: // 假设读取到的字符串Hello的首地址为0x000 &ptr = 0x000; // 此时ptr就指向了Hello
-
n:如果是由系统malloc的指针填0;
-
stream:函数需要读取的FILE流
-
返回值:成功返回读取的字节数,失败或读完返回-1。
代码示例:
int main(int argc, char **argv) { FILE *fp; // 一定要初始化,否则指针会指向内存中的随机位置 char *linebuf = NULL; size_t linesize = 0; if(argc < 2) { fprintf(stderr, "Usage... "); } fp = fopen(argv[1], "r"); if(fp == NULL) { perror("fopen()"); exit(1); } while(1) { // 当返回-1时则读完 if(getline(&linebuf, &linesize, fp) < 0) break; printf("%d ", strlen(linebuf)); } fclose(fp); exit(0); }