天天看點

熬夜整理的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

成功:實際成功讀取到内容的塊數,如果此值比nmemb小,但大于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字元串來轉換并格式化資料。

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

功能:移動檔案流(檔案光标)的讀寫位置。

offset:根據 whence 來移動的位移數(偏移量),可以是正數,也可以負數,如果正數,則相對于 whence 往右移動,如果是負數,則相對于 whence 往左移動。如果向前移動的位元組數超過了檔案開頭則出錯傳回,如果向後移動的位元組數超過了 檔案末尾,再次寫入時将增大檔案尺寸。

whence:其取值如下:

SEEK_SET:從檔案開頭移動offset個位元組

SEEK_CUR:從目前位置移動offset個位元組

SEEK_END:從檔案末尾移動offset個位元組

成功:0

long ftell(FILE *stream);

功能:擷取檔案流(檔案光标)的讀寫位置。

參數:stream:已經打開的檔案指針

成功:目前檔案流(檔案光标)的讀寫位置

void rewind(FILE *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;
}

      

繼續閱讀