熬夜整理的C语言/C++万字总结(六)

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;
}

上一篇:熬夜为学弟学妹整理的网络编程基础知识(一)!


下一篇:呐,c语言学习你想要的都在这里