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