1.2.4.2 行读写函数
int fputs(const char * str, FILE * stream);
功能:将 str 所指定的字符串写入到 stream 指定的文件中, 字符串结束符 '\0' 不写入文件。
参数:
str:字符串。 stream:文件指针
返回值:
成功:0。 失败:-1
char * fgets(char * str, int size, FILE * stream);
功能:从 stream 指定的文件内读入字符,保存到 str 所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了 size - 1 个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
参数:
str:字符串。
size:指定最大读取字符串的长度(size - 1)。
stream:文件指针
void test(){ //写文件 FILE* fp_write= NULL; //写方式打开文件 fp_write = fopen("./mydata.txt", "w+"); if (fp_write == NULL){ perror("fopen:"); return; } char* buf[] = { "01 this is a test for pfutc!\n", "02 this is a test for pfutc!\n", "03 this is a test for pfutc!\n", "04 this is a test for pfutc!\n", }; for (int i = 0; i < 4; i ++){ fputs(buf[i], fp_write); } fclose(fp_write); //读文件 FILE* fp_read = NULL; fp_read = fopen("./mydata.txt", "r"); if (fp_read == NULL){ perror("fopen:"); return; } //判断文件结尾 while (!feof(fp_read)){ char temp[1024] = { 0 }; fgets(temp, 1024, fp_read); printf("%s",temp); } fclose(fp_read); }
1.2.4.3 块读写函数
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式给文件写入内容。
参数:
ptr:准备写入文件数据的地址
size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb
stream:已经打开的文件指针
返回值:
成功:实际成功写入文件数据的块数,此值和nmemb相等
失败:0
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式从文件中读取内容
参数:
ptr:存放读取出来数据的内存空间
size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
stream:已经打开的文件指针
返回值:
成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
失败:0
typedef struct _TEACHER{ char name[64]; int age; }Teacher; void test(){ //写文件 FILE* fp_write= NULL; //写方式打开文件 fp_write = fopen("./mydata.txt", "wb"); if (fp_write == NULL){ perror("fopen:"); return; } Teacher teachers[4] = { { "Obama", 33 }, { "John", 28 }, { "Edward", 45}, { "Smith", 35} }; for (int i = 0; i < 4; i ++){ fwrite(&teachers[i],sizeof(Teacher),1, fp_write); } //关闭文件 fclose(fp_write); //读文件 FILE* fp_read = NULL; fp_read = fopen("./mydata.txt", "rb"); if (fp_read == NULL){ perror("fopen:"); return; } Teacher temps[4]; fread(&temps, sizeof(Teacher), 4, fp_read); for (int i = 0; i < 4;i++){ printf("Name:%s Age:%d\n",temps[i].name,temps[i].age); } fclose(fp_read); }
1.2.4.4 格式化读写函数
int fprintf(FILE * stream, const char * format, ...);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0' 为止。 参数:
stream:已经打开的文件
format:字符串格式,用法和printf()一样
返回值:
成功:实际写入文件的字符个数
失败:-1
int fscanf(FILE * stream, const char * format, ...);
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
stream:已经打开的文件
format:字符串格式,用法和scanf()一样
返回值:
成功:实际从文件中读取的字符个数
失败: - 1
注意:fscanf遇到空格和换行时结束。
void test(){ //写文件 FILE* fp_write= NULL; //写方式打开文件 fp_write = fopen("./mydata.txt", "w"); if (fp_write == NULL){ perror("fopen:"); return; } fprintf(fp_write,"hello world:%d!",10); //关闭文件 fclose(fp_write); //读文件 FILE* fp_read = NULL; fp_read = fopen("./mydata.txt", "rb"); if (fp_read == NULL){ perror("fopen:"); return; } char temps[1024] = { 0 }; while (!feof(fp_read)){ fscanf(fp_read, "%s", temps); printf("%s", temps); } fclose(fp_read); }
1.2.5.5 随机读写函数
int fseek(FILE *stream, long offset, int whence);
功能:移动文件流(文件光标)的读写位置。
参数:
stream:已经打开的文件指针
offset:根据 whence 来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于 whence 往右移动,如果是负数,则相对于 whence 往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了 文件末尾,再次写入时将增大文件尺寸。
whence:其取值如下:
SEEK_SET:从文件开头移动offset个字节
SEEK_CUR:从当前位置移动offset个字节
SEEK_END:从文件末尾移动offset个字节
返回值:
成功:0
失败:-1
long ftell(FILE *stream);
功能:获取文件流(文件光标)的读写位置。
参数:stream:已经打开的文件指针
返回值:
成功:当前文件流(文件光标)的读写位置
失败:-1
void rewind(FILE *stream);
功能:把文件流(文件光标)的读写位置移动到文件开头。
参数:stream:已经打开的文件指针
返回值:无返回值
typedef struct _TEACHER{ char name[64]; int age; }Teacher; void test(){ //写文件 FILE* fp_write = NULL; //写方式打开文件 fp_write = fopen("./mydata.txt", "wb"); if (fp_write == NULL){ perror("fopen:"); return; } Teacher teachers[4] = { { "Obama", 33 }, { "John", 28 }, { "Edward", 45 }, { "Smith", 35 } }; for (int i = 0; i < 4; i++){ fwrite(&teachers[i], sizeof(Teacher), 1, fp_write); } //关闭文件 fclose(fp_write); //读文件 FILE* fp_read = NULL; fp_read = fopen("./mydata.txt", "rb"); if (fp_read == NULL){ perror("fopen:"); return; } Teacher temp; //读取第三个数组 fseek(fp_read , sizeof(Teacher) * 2 , SEEK_SET); fread(&temp, sizeof(Teacher), 1, fp_read); printf("Name:%s Age:%d\n",temp.name,temp.age); memset(&temp,0,sizeof(Teacher)); fseek(fp_read, -(int)sizeof(Teacher), SEEK_END); fread(&temp, sizeof(Teacher), 1, fp_read); printf("Name:%s Age:%d\n", temp.name, temp.age); rewind(fp_read); fread(&temp, sizeof(Teacher), 1, fp_read); printf("Name:%s Age:%d\n", temp.name, temp.age); fclose(fp_read); }
1.4 文件读写案例
读写配置文件
配置文件格式如下:
正式的数据以 ‘:’ 冒号进行分割,冒号前为 key 起到索引作用,冒号后为 value 是实值。# 开头的为注释,而不是正式数据
#英雄的Id heroId:1 #英雄的姓名 heroName:德玛西亚 #英雄的攻击力 heroAtk:1000 #英雄的防御力 heroDef:500 #英雄的简介 heroInfo:前排坦克
struct ConfigInfo { char key[64]; char value[64]; }; //获取文件有效行数 int getFileLine(const char * filePath) { FILE * file = fopen(filePath, "r"); char buf[1024] = {0}; int lines = 0; while (fgets(buf,1024,file) != NULL) { if (isValidLine(buf)) { lines++; } memset(buf, 0, 1024); } fclose(file); return lines; } //解析文件 void parseFile(const char * filePath, int lines, struct ConfigInfo** configInfo) { struct ConfigInfo * pConfig = malloc(sizeof(struct ConfigInfo) * lines); if (pConfig == NULL) { return; } FILE * file = fopen(filePath, "r"); char buf[1024] = { 0 }; int index = 0; while (fgets(buf, 1024, file) != NULL) { if (isValidLine(buf)) { //解析数据到struct ConfigInfo中 memset(pConfig[index].key, 0, 64); memset(pConfig[index].value, 0, 64); char * pos = strchr(buf, ':'); strncpy(pConfig[index].key, buf, pos - buf); strncpy(pConfig[index].value, pos + 1, strlen(pos + 1) - 1); // 从第二个单词开始截取字符串,并且不截取换行符 //printf("key = %s\n", pConfig[index].key); //printf("value = %s\n", pConfig[index].value); index++; } memset(buf, 0, 1024); } *configInfo = pConfig; } //获取指定的配置信息 char * getInfoByKey(char * key, struct ConfigInfo*configInfo ,int lines) { for (int i = 0; i < lines;i++) { if (strcmp(key, configInfo[i].key) == 0) { return configInfo[i].value; } } return NULL; } //释放配置文件信息 void freeConfigInfo(struct ConfigInfo*configInfo) { free(configInfo); configInfo = NULL; } //判断当前行是否为有效行 int isValidLine(char * buf) { if (buf[0] == '0' || buf[0] == '\0' || strchr(buf,':') == NULL) { return 0;// 如果行无限 返回假 } return 1; } int main(){ char * filePath = "./config.txt"; int lines = getFileLine(filePath); printf("文件有效行数为:%d\n", lines); struct ConfigInfo * config = NULL; parseFile(filePath, lines, &config); printf("heroId = %s\n", getInfoByKey("heroId", config, lines)); printf("heroName: = %s\n", getInfoByKey("heroName", config, lines)); printf("heroAtk = %s\n", getInfoByKey("heroAtk", config, lines)); printf("heroDef: = %s\n", getInfoByKey("heroDef", config, lines)); printf("heroInfo: = %s\n", getInfoByKey("heroInfo", config, lines)); freeConfigInfo(config); config = NULL; system("pause"); return EXIT_SUCCESS; }