前面一篇博客写了关于高级io对于文件的一些操作函数,下面讲一下与文件流的定位相关的函数;即移动文件读写位置相关的操作。
一. fseek()/ftell()
头文件 | #include <stdio.h> |
函数 | int fseek(FILE *stream, long offset, int whence); long ftell(FILE *stream); |
功能说明 | Feek():用来移动文件流的读写位置。 Ftell():用来获取文件读写指针的当前所在位置。 |
参数说明 | Offet:所需移动的文件指针的偏移量 Whence: 参数 为下列其中一种: SEEK_SET从距文件开头offset位移量为新的读写位置。 SEEK_CUR 以目前的读写位置往后增加offset个位移量。 SEEK_END将读写位置指向文件尾后再增加offset个位移量。 |
注意:(a) fseek()/ftell() 调用成功时则返回0,若有错误则返回-1,errno会存放错误代码。
(b) ftell() 经常和 fseek() 一起使用。使用fseek函数后再调用函数ftell()就能非常容易地确定文件的当前位置。
头文件 | #include <stdio.h> |
函数 | void rewind(FILE *stream); |
功能说明 | 将文件指针重新指向文件的开头,同时清除和文件流相关的错误和eof标记,相当于调用fseek(stream, 0, SEEK_SET) |
参数说明 |
|
三 fclose()
头文件 | #include <stdio.h> |
函数 | int fclose(FILE *fp); |
功能说明 | 调用成功返回0,调用失败返回-1,并设置errno的值,如果程序结束前没有执行流动关闭操作,有可能会造成写入的数据停留在缓冲区里没有保存到文件中,从而造成数据的丢失。 |
参数说明 |
|
四 fflush()/fsync()
头文件 | #include <stdio.h> |
函数 | int fflush(FILE *stream); |
功能说明 | 是把C库中的缓冲调用write函数写到磁盘[其实是写到内核的缓冲区] |
参数说明 | Stream:文件指针 |
头文件 | #include <unistd.h> |
函数 | int fsync(int fd); |
功能说明 | 把内核缓冲刷到磁盘上。 |
参数说明 | Stream:文件描述符 |
注意:刷新缓冲区的流程:c库缓冲----->fflush---------〉内核缓冲-------->fsync-----〉磁盘
五 tmpfile()/tmpnam
在讲这两个函数前先说下临时文件的概念:临时文件是指那些在程序运行期间存在并使用,而当程序运行完之后就删除的文件,临时文件的操作都是在基于流的基础上进行的。
头文件 | #include <stdio.h> |
函数 | FILE *tmpfile(void); |
功能说明 | 用于打开一个临时文件,该函数将创建一个临时二进制文件,该文件会在程序结束后自动删除,调用tmpfile生成临时文件时,它首先会调用函数tmpnam生产临时文件的文件名,然后创建这一文件,在程序结束时,系统调用ulink函数,文件将会删除。 |
参数说明 |
|
头文件 | #include <stdio.h> |
函数 | char *tmpnam(char *s); |
功能说明 | tmpnam作用是生成一个有效的文件名,该文件名不同于任何一个已经存在的文件名,s 指向用于保存新生成文件名的缓冲区。该缓冲区长度要大于等于L_tmpnam,该常数在stdio库中定义。调用成功返回该缓冲区的指针,如果参数为NULL,则在静态缓冲区中存放生成的文件名,但是要再次调用该函数时将改变这一区域中的文件名,因此,如果要保存文件名的话,必须要开辟相应的缓冲区来存放文件名。当调用失败是返回空指针。此外,tmpnam调用次数有所限制,必须小于等于TMP_MAX的值,该值在stdio库中定义。 |
参数说明 | S:用户自定用来存储生成的临时文件的名字的缓冲区的指针 |
六 setbuf()/setvbuf()
头文件 | #include <stdio.h> |
函数 | void setbuf(FILE *stream, char *buf); |
功能说明 | 用于将缓冲区设置为全缓冲或无缓冲,buf为指向缓冲区的指针。当buf指向一个真实缓冲区地址时,将缓冲区设置为全缓冲,大小有常数BUFSIZE指定,当buf为NULL时,则设定为无缓冲,此函数一般用作激活或禁止缓冲区的开关。 |
参数说明 | Stream:文件流 ,buf缓冲区的指针 |
头文件 | #include <stdio.h> |
函数 | int setvbuf(FILE *stream, char *buf, int mode, size_t size); |
功能说明 | 用来设定文件流的缓冲区 |
参数说明 | stream为文件流指针,buf为缓冲区首地址,type为缓冲区类型,size为缓冲区内字节的数量。 |
注意:
(1)setbuf()和setvbuf()函数的实际意义在于:用户打开一个文件后,可以建立自己的文件缓冲区,而不必使用fopen()函数打开文件时设定的默认缓冲区。这样就可以让用户自己来控制缓冲区,包括改变缓冲区大小、定时刷新缓冲区、改变缓冲区类型、删除流中默认的缓冲区、为不带缓冲区的流开辟缓冲区等。
(2)在打开文件流后,读取内容之前,调用setvbuf()可以用来设置文件流的缓冲区(而且必须是这样)。
七 最后说下高级IO操作其它的问题
(1) 其实创建缓冲区并不是越大越好。
(2) 标准io在调用fopen()时就已经创建缓存区
(3) 优先选择:
fgets();/fputs();
fread();/fwrite();
八 实例
/************************************/
//函数功能:创建一个文件具有读写权限;向创建的新的文件fp1所指向写入固定的内容,在将一段任意指定的内容插入到第三行;
//
/************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 1024
int main(int argc,char **argv)
{
unsigned char buf[BUFSIZE] = {};
unsigned char i,j=0; //用来记录需要写入的行数
unsigned char flag = 0; //标志位
unsigned char *str = "wellcom to china\n";//写向fp1的内容
unsigned char *str1 = "hahaha\n";//写向fp1的内容
FILE * fp1 = NULL; //用来指向原始的文件
FILE * fp2 = NULL; //用来指向临时文件指针
fp1 = fopen(argv[1],"w+"); //不存在则创建
if(fp1 == NULL){
perror("fopen()");
exit(1);
}
/****************向fp1中写入10行str所指向的内容**********************/
for(i=0;i<10;i++)
{
if(fputs(str,fp1) == EOF){
printf("fputs is error\n");
exit(1);
}
}
fp2 = tmpfile(); //创建临时文件
if(fp2 == NULL){
perror("tmpfile()");
exit(1);
}
rewind(fp1);//将文件指针重新定向到文件的起始位置
rewind(fp2);
while(1) //将临时文件的内容,复制到fp1所指向文件,并将“hahaha”插入到fp2的第三行
{
if (fgets(buf, BUFSIZE, fp1) == NULL) {break;}
fputs(buf, fp2);
if (strlen(buf) < BUFSIZE-1 || buf[BUFSIZE-2] == '\n')
j++;
if (j == 2 && !flag) {
fputs(str1, fp2);
flag = 1;
}
}
rewind(fp1);//重新将文件指针指向文件的起始位置
rewind(fp2);
while(1){ //将临时文件的内容,复制到fp1所指向文件
if(fgets(buf,BUFSIZE,fp2)== NULL) break;
if(fputs(buf,fp1) == EOF) break;
}
exit(0);
}