系统自动的在内存里面为每一个正在使用的文件开辟一个缓冲区,从内存向磁盘输出数据必须先送到内存缓冲区,装满缓冲区,在一起送到磁盘里面。从内存向磁盘读取数据,则一次从磁盘文件中将一批数据读到内存缓冲区中,然后再从缓冲区中将数据送到程序的数据区。
例如:需要将1024 个字节写到文件中去,每次写一个字节。
如果是文件IO,则要进行1024次 写操作,将1024个字节挪到内核,然后到磁盘。
如果使用标准IO的话,会现将数据写到缓冲区中,然后等到缓冲区满了,或者刷新了缓冲区,才整体将这些数据写入磁盘。只执行一次写操作即可,一次数据挪动即可。
标准IO函数是根据文件流关联的设备类型,会选择采用何种缓冲区的操作方式。分类如下:
缓冲区是通过malloc申请的空间
申请的实际,是发生I/O操作的时候
进程结束会默认刷新缓冲区。
函数原型
FILE *fopen(const char *filename, const char *mode)
filename : 文件名称
mode 模式 :
模式 | 说明 |
---|---|
“r” | 打开一个用于读取的文件。该文件必须存在。 |
“w” | 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。 |
“a” | 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。 |
“r+” | 打开一个用于更新的文件,可读取也可写入。该文件必须存在。 |
“w+” | 创建一个用于读写的空文件。 |
“a+” | 打开一个用于读取和追加的文件。 |
返回值:
该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。
函数原型:
int fgetc(FILE *stream); //从stream流中读取一个字符
int getc(FILE *stream); //从stream流中读取一个字符
int getchar(void); //从stdin标准输入流中流中读取一个字符
返回值
该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
函数原型:
int fputc(int c, FILE *stream) // 将一个字符输出到stream流中
int putc(int c, FILE *stream);// 将一个字符输出到stream流中
int putchar(int c);// 将一个字符输出到stdout(标准输出)流中
返回值:
如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
只能读取文本文件,不能读取二进制文件,因为在读取二进制文件的时候会将0认为是\0,导致0这个数据丢失。
从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
函数原型:
char *fgets(char *str, int n, FILE *stream)
char *gets(char *str); 从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间
gets因为不知道顶读取数据的大小可能会导致内存超出
返回值:
如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
gets() 和 fgets的区别:
gets() 会将回车读取出来并丢弃,所以换行符不会像 scanf 那样被保留在缓冲区,也不会被 gets() 存储;而使用 fgets() 时,换行符会被 fgets() 读出来并存储在字符数组的最后,这样当这个字符数组被输出时换行符就会被输出并自动换行。
当指定的长度小于读取的长度的时候:
用 fgets() 时指定了读取的长度,如只读取 5 个字符,事实上它只能存储 4 个字符,因为最后还要留一个空间给 ‘\0’,而你却从键盘输入了多于 4 个字符,那么此时“敲”回车后换行符就不会被 fgets() 存储。数据都没有地方存放,哪有地方存放换行符呢!此时因为 fgets() 没有存储换行符,所以就不会换行了
reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the buffer.
A terminating null byte (‘\0’) is stored after the last character in the buffer
函数原型:
int fputs(const char *s, FILE *stream);
int puts(const char *s); // = fputs(const char *s, stdout);
fputs() 和 puts() 有两个小区别:
puts() 只能向标准输出流输出,而 fputs() 可以向任何流输出。
使用 puts() 时,系统会在自动在其后添加换行符;而使用 fputs() 时,系统不会自动添加换行符。
返回值:
该函数返回一个非负值,如果发生错误则返回 EOF。
可以运用与文本文件和二进制文件
函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
参数:
返回值:
如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误。
可以运用与文本文件和二进制文件
函数原型:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
给定流 stream 读取数据到 ptr 所指向的数组中。
返回值:
成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。
int fseek(FILE *stream, long int offset, int whence)
SEEK_SET | 文件的开头 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件的末尾 |
返回值:
如果成功,则该函数返回零,否则返回非零值。
long int ftell(FILE *stream) 返回给定流 stream 的当前文件位置。
返回值:
该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。
void rewind(FILE *stream) 设置文件位置为给定流 stream 的文件的开头。
int ferror(FILE *stream)
如果设置了与流关联的错误标识符,该函数返回一个非零值,否则返回一个零值。
int feof(FILE * stream);
当设置了与流关联的文件结束标识符时(表示读写位置已经到文件末尾),该函数返回一个非零值,否则返回零。
功能:
#include
#include
#include
#include
#include
//gcc -o bin/io_practice src/io_practice.c
struct tm get_cur_tm()
{
time_t timep;
if((timep = time(NULL)) < 0){
perror("time:");
exit(1);
}
struct tm *ltimep;
if((ltimep = localtime(&timep)) == NULL){
perror("localtime:");
exit(1);
}
return *ltimep;
}
int get_total_line(FILE *fp)
{
char buff[1024];
int line = 0;
while(fgets(buff, sizeof(buff), fp) != NULL){
if(buff[strlen(buff) - 1] == '\n'){
line ++;
}
}
return line;
}
int main(int argc, char *argv[])
{
if(argc < 2){
fprintf(stderr,"usage: %s \n" , argv[1]);
}
FILE *fp;
if((fp = fopen(argv[1], "a+")) == NULL){
perror("fopen:");
exit(1);
}
struct tm cur_time;
int line = 1;
line = get_total_line(fp);
while(1){
printf("write date line %d\n", line);
cur_time = get_cur_tm();
fprintf(fp, "%d. %d-%02d-%02d %02d:%02d:%02d\n",
line,cur_time.tm_year + 1900, cur_time.tm_mon, cur_time.tm_mday,
cur_time.tm_hour, cur_time.tm_min, cur_time.tm_sec);
fflush(fp);
// 每格一秒钟后写入数据
sleep(1);
line ++;
}
return 0;
}
fflush(FILE *fp)
进程结束的时候,清空缓冲区