本文已整合到C语言标准库深度解读
打开文件
fopen
和freopen
均为C语言标准库stdio.h
中的函数,分别用于打开和重新打开某个stream,二者均返回一个FILE
指针。
- FILE *fopen(const char *filename, const char *mode)
- FILE *freopen(const char *filename, const char *mode, FILE *stream)
其中filename为文件路径,mode为文件打开模式,freopen中输入的的stream为现存的流,freopen将新打开的文件注入stream中,同时关闭旧文件。
其中mode
的取值如下,第一列为常规模式,第二列为二进制模式,在二进制模式下,读取的是二进制文件,其他与常规模式相同。
mode | 模式 | 说明 | |
---|---|---|---|
“r” | “rb” | 只读 | 打开的文件必须存在。 |
“w” | “wb” | 写入 | 创建一个空文件,若文件已存在,会删除原有内容。 |
“a” | “ab” | 追加 | 向文件末尾追加数据,若文件不存在,则创建文件。 |
“r+” | “rb+” | 更新 | 打开一个文件进行读写,该文件必须存在。 |
“w+” | “wb+” | 读写 | 创建一个用于读写的空文件。 |
“a+” | “ab+” | 打开一个用于读取和追加的文件 |
fopen
和freopen
的返回值为FILE
指针,刚好可以通过stdio.h
中的close
进行关闭。
关于FILE
这个结构体,可见FILE结构体。
文件读写
在stdio.h
中定义了读、写还有移动指针的函数,其中fread
用于将文件中的数据写入内存;fwrite
将内存中的数据写入文件;fseek
则操作文件指针,使之偏移,从而可以更加灵活地读取。
- 读:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
- 写:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
- 移:int fseek(FILE *stream, long int offset, int whence)
其中,ptr
为指向某个内存块的指针;stream
为文件的数据流;nmemb
为元素个数,size
为每个元素的字节数;whence
为添加偏移的位置,offset
为相对于whence
的偏移量。
在stdio.h
中为whence
定义了宏,其含义如下
#define SEEK_SET 0 | 从0开始 |
#define SEEK_CUR 1 | 从当前位置开始 |
#define SEEK_END 2 | 从EOF开始 |
读写相对来说比较直观,接下来主要测试一下fseek
,说明均在注释中。
//test.c
#include<stdio.h>
void printChar(char *buffer, int len){
for(int i = 1; i < len; i++)
printf("%c",buffer[i-1]);
printf("\n-------------------------\n");
}
int main(){
FILE* fp = fopen("test.c","r"); //打开test.c文件,即本文件
char buf[20];
fread(buf,1,20,fp); //读取fp中的数据
printf("printf the first 20 bytes:");
printChar(buf,20);
fseek(fp, 24, SEEK_CUR); //从当前位置开始偏移
fread(buf,1,20,fp);
printf("fseek 24 from now:");
printChar(buf,20);
fseek(fp, 24, SEEK_SET); //从0开始偏移
fread(buf,1,20,fp);
printf("fseek 24 from 0:");
printChar(buf,20);
fseek(fp, -20, SEEK_END); //从结束位置向前偏移
fread(buf,1,20,fp);
printf("fseek 20 from END:");
printChar(buf,20);
fclose(fp); //关闭fp
return 0;
}
输出结果为
>gcc test.c
E:\Documents\00\1217>a.exe
printf the first 20 bytes://test.c
#include<s
-------------------------
fseek 24 from now:har *buffer, int le
-------------------------
fseek 24 from 0:.h>
void printChar(
-------------------------
fseek 20 from END:
return 0;
}
r(
-------------------------
文件定位
除了fseek
可以对文件指针进行移动之外,fsetpos
可以直接对文件指针进行定位。相应地,fgetpos
可以获取文件指针的位置,二者声明为:
int fgetpos(FILE *stream, fpos_t *pos)
int fsetpos(FILE *stream, const fpos_t *pos)
二者的返回值均为设置之后的位置,关于输入参数,FILE *stream
是大家非常熟悉的文件流,而fpos_t
是一个结构体,代表相对位置,通常定义为
typedef struct
{
unsigned long _off;
}fpos_t;
接下来做一个简单的测试
//pos.c
#include <string.h>
#include <stdio.h>
int main(void)
{
fpos_t pos;
FILE* fp = fopen("pos.c", "r"); //打开pos.c文件,即本文件
fgetpos(fp, &pos); //获取指针位置
printf("file pointer : %ld\n", pos);
fseek(fp,10,0); // 移动指针位置
fgetpos(fp, &pos); // 获取指针位置并存入&pos所指向的对象
printf("file pointer : %ld\n", pos);
fclose(fp);
return 0;
}
结果如下,可见getpos
和fseek
的单位是一致的,fseek
移动了10个字节,则fgetpos
也获取了位置10.
>gcc pos.c
>a.exe
file pointer : 0
file pointer : 10
结合fgetpos
和fsetpos
,可完成类似fseek
的操作
//setpos.c
#include <string.h>
#include <stdio.h>
int main(void)
{
fpos_t pos;
FILE* fp = fopen("pos.c", "r"); //打开pos.c文件,即本文件
printf("file pointer : %ld\n", fgetpos(fp, &pos));
pos += 10;
fsetpos(fp, &pos); //设置指针位置
printf("file pointer : %ld\n", fgetpos(fp, &pos));
fclose(fp);
return 0;
}
测试结果为
>gcc setpos.c
>a.exe
file pointer : 0
file pointer : 10