目錄
1.?什么是文件
1.1 程序文件
1.2?數據文件
1.3 文件名?
2.?二進制文件和文本文件
3.?文件的打開與關閉
3.1 流和標準流
3.2?文件指針
3.3 文件的打開與關閉
fopen?
fclose
4.?文件的順序讀寫
4.1 fgetc和fputc?
?fgetc
fputc
4.2 fgets和fputs
fgets
fputs?
4.3 scanf / fscanf / sscanf
scanf?
fscanf
sscanf
4.4?printf / sprintf / fprintf
printf
fprintf
?sprintf
4.5?fread和fwrite
fread
fwrite
5. 文件的隨機讀寫
fseek
ftell
rewind
6. 文件讀取結束的判定
7. 文件緩沖區
1.?什么是文件
磁盤(硬盤)上的文件就是文件
????????
但是在程序設計中,我們?般談的文件有兩種:程序文件、數據文件
1.1 程序文件
程序文件包括源程序文件(后綴為.c),目標文件(windows環境后綴為.obj),可執行程序(windows 環境后綴為.exe)
1.2?數據文件
就是程序運行時讀寫的數據,比如程序運行需要從中讀取數據的文件,或者輸出內容的文件
1.3 文件名?
?個文件要有?個唯?的文件標識(文件標識常被稱為文件名),以便用戶識別和引用,文件名包含3部分:文件路徑 + 文件名主干 + 文件后綴
例如: c:\code\test.txt
c:\code\:表示文件路徑 ? ? ?test:表示文件名主干 ? ? ?.txt:表示文件后綴
2.?二進制文件和文本文件
根據數據的組織形式,數據文件被稱為文本文件和二進制文件
????????
二進制文件:二進制文件就是把內存中的數據按其在內存中存儲的形式原樣存儲在磁盤上
????????
文本文件:如果要求在外存上以ASCII碼的形式存儲,則需要在存儲前轉換。以ASCII字符的形式存儲的?件就是文本文件
?
數據在內存中如何存儲呢?
????????
字符?律以ASCII形式存儲,數值型數據既可以用ASCII形式存儲,也可以使用二進制形式儲
????????
如有整數10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占用5個字節(每個字符?個字節),而?進制形式輸出,則在磁盤上只占4個字節
#include<stdio.h>
#include<stdlib.h>
int main()
{int a = 100;FILE* pa = fopen("text.txt", "wb");fwrite(&a, 4, 1, pa);fclose(pa);pa == NULL;return 0;
}
3.?文件的打開與關閉
????????
3.1 流和標準流
我們從鍵盤輸入數據,向屏幕上輸出數據,并沒有打開流呢?那是因為C語言程序在啟動的時候,默認打開了3個流:
????????
stdin - 標準輸?流,在?多數的環境中從鍵盤輸?,scanf函數就是從標準輸?流中讀取數據
????????
stdout - 標準輸出流,?多數的環境中輸出至顯示器界?,printf函數就是將信息輸出到標準輸出流中????????
stderr - 標準錯誤流,?多數環境中輸出到顯示器界?????????
頭文件為:
????????
#include<stdio.h>
stdin、stdout、stderr 三個流的類型是: FILE* ,通常稱為文件指針
????????
C語言中,就是通過 FILE* 的文件指針來維護流的各種操作的?
3.2?文件指針
文件類型指針簡稱件指針
每個被使用的文件都在內存中開辟了一個相應的文件信息區,用來存放文件的相關信息(如文件的名字,文件狀態及文件當前的位置等)。這些信息是保存在一個結構體變量中的。該結構體類型是由系統聲明的,取名FILE
我們可以在編譯環境提供的 stdio.h 頭?件中有以下的?件類型申明:
struct _iobuf {char* _ptr;int _cnt;char* _base;int _flag;int _file;int _charbuf;int _bufsiz;char* _tmpfname;
};
typedef struct _iobuf FILE;
?不同的C編譯器的FILE類型包含的內容不完全相同,但是大同小異
????????
每當我們打開一個文件的時候,系統會根據文件的情況自動創建一個FILE結構的變量,并填充其中的信息,該變量就指向了文件信息區,通過該指針就可以找到文件
我們可以創造一個文件指針變量來接收打開文件后返回的變量,該指針變量就可以訪問該文件
FILE*pf;
定義pf是一個指向FILE類型數據的指針變量。可以使pf指向某個文件的文件信息區(是一個結構體變量)
????????
通過該文件信息區中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它關聯的文件
3.3 文件的打開與關閉
文件在讀寫之前應該先打開文件,在使用結束之后應該關閉文件
????????
在編寫程序的時候,在打開文件的同時,都會返回?個FILE*的指針變量指向該文件,也相當于建立了?指針和文件的關系
????????
?ANSIIC規定使用fopen 函數來打開文件, fclose 來關閉文件
fopen?
fopen文檔鏈接:
????????
fopen - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fopen/?kw=fopen
//打開?件
FILE * fopen ( const char * filename, const char * mode );
其功能是使用給定的模式 mode 打開 filename 所指向的文件。文件順利打開后,指向該流的文件指針就會被返回。如果文件打開失敗則返回?NULL,并把錯誤代碼存在 error 中
fclose
fclose文檔鏈接:
????????
fclose - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fclose/?kw=fclose
//關閉?件
int fclose ( FILE * stream );
返回值:如果流成功關閉,fclose 返回 0,否則返回EOF(-1)(如果流為NULL,而且程序可以繼續執行,fclose設定error number給EINVAL,并返回EOF)
當時用"w"、"wb"、"w+"、"wb+"這些打開方式時會清除文件原本存儲的數據?
/* fopen fclose example */
#include <stdio.h>
int main()
{FILE* pFile;//打開?件pFile = fopen("myfile.txt", "w");//?件操作if (pFile != NULL){fputs("fopen example", pFile);//關閉?件fclose(pFile);}return 0;
}
4.?文件的順序讀寫
4.1 fgetc和fputc?
?fgetc
fgetc文檔鏈接:
????????
fgetc - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fgetc/?kw=fgetc
int fgetc ( FILE * stream );
從文件指針stream指向的文件中讀取一個字符,該字符的ASCII值作為函數的返回值,讀取一個字節后光標向后移一個字節,若返回值為EOF,說明文件結束,EOF是文件結束標志,值為-1?
int main()
{FILE* pb = fopen("text.txt", "r");//為輸入打開一個文本文件if (pb == EOF)//判斷是否打開成功{perror("fopen");return 1;}int ch = 0;while ((ch = fgetc(pb)) != EOF)//判斷是否成功輸入數據{printf("%c", ch);//成功讀取則將外部文件中的數據輸入到程序中}printf("\n");fclose(pb);//關閉文件pb == NULL;//將pb置為空指針return 0;
}
fputc
fputc文檔鏈接:
????????
fputc - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fputc/?kw=fputc
int fputc ( int character, FILE * stream );
返回值:
????????
在正常調用情況下,函數返回寫入文件的字符的ASCII碼值,出錯時,返回EOF(-1)。當正確寫入一個字符或一個字節的數據后,文件內部寫指針會自動后移一個字節的位置
int main()
{FILE* pa = fopen("text.txt", "w");//打開文件,打開方式為輸出數據wif (pa == NULL)//判斷是否打開成功{perror("fopen");return 1;}for (int i = 0; i < 26; i++)//成功打開后則把程序中的數據輸出到外部文件中{int ret = fputc('a' + i, pa);printf("%c", ret);}//判斷是否關閉文件成功if (fclose(pa) == EOF){perror("fclose");return 1;}pa == NULL;//將pa置為空指針,防止野指針return 0;
4.2 fgets和fputs
?
fgets
fgets文檔鏈接:
????????
fgets - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fgets/?kw=fgets
char * fgets ( char * str, int num, FILE * stream );
從指定的流 stream 讀取一行(每次最多只能從文件中讀取一行內容,因為 fgets遇到換行符就結束讀取),并把它存儲在 str 所指向的字符串內。當讀取 (n-1) 個字符時或者讀取到換行符時又或者到達文件末尾時,它會停止,具體視情況而定
????????
如果文件中的該行,不足n-1個字符,則讀完該行就結束。如若該行(包括最后一個換行符)的字符數超過n-1,則fgets只返回一個不完整的行
返回值:
????????
1. 如果成功,該函數返回str的頭指針
????????
2. 如果到達文件末尾或者沒有讀取到任何字符,str 的內容保持不變,并返回一個空指針
????????
3. 如果發生錯誤,返回一個空指針
int main()
{FILE* pc = fopen("text.txt", "r");//為了輸入數據打開文件if (pc == NULL)//判斷是否打開成功{perror("fopen");return 1;}char arr[30] = { 0 };//創造數組//將讀取到的字符串串存儲到arr指向的字符串內,如果外部文件中有兩行字符串,只需再讀取一次fgets(arr, 26 + 1, pc);puts(arr); //打印字符串fclose(pc);//關閉文件pc = NULL;//置為空指針return 0;
}
fputs?
fputs文檔鏈接:
????????
fputs - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fputs/?kw=fputs
int fputs ( const char * str, FILE * stream );str:一個數組,包含了要寫入的以空字符終止的字符序列stream:指向 FILE 對象的指針,該 FILE 對象標識了要被寫入字符串的流
函數功能是向指定的文件寫入一個字符串(不自動寫入字符串結束標記符‘\0’),成功寫入一個字符串后,文件的位置指針會自動后移
????????
該函數返回一個非負值,如果發生錯誤則返回 EOF(-1)
int main()
{FILE* pd = fopen("1.txt", "w");//為了將程序中的數據輸入到外部文件,打開文件if (pd == NULL)//判斷{perror("fopen");return 1;}char arr[20] = "sjjwdjtmkadkiana";//創建數組if ((fputs(arr, pd)) == EOF)//判斷是否輸入成功{perror("fputs");return 1;}if (fclose(pd) == EOF)//判斷是否關閉成功{perror("fclose");return 1;}pd = NULL;return 0;
}
4.3 scanf / fscanf / sscanf
函數 | 功能 |
---|---|
scanf | 從標準輸入流上讀取格式化的數據 |
fscanf | 從指定的輸入流上讀取格式化的數據 |
sscanf | 在字符串中讀取格式化的數據 |
?????????
scanf?
scanf文檔鏈接:
????????
cplusplus.com/reference/cstdio/scanf/
https://cplusplus.com/reference/cstdio/scanf/
int scanf ( const char * format, ... );
?
函數的第一個參數是格式字符串,它指定了輸入的格式,并按照格式說明符解析輸入對應位置的信息并存儲于可變參數列表中對應的指針所指位置
????????
每一個指針要求非空,并且與字符串中的格式符一一順次對應
fscanf
fscanf文檔鏈接:
????????
fscanf - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fscanf/?kw=fscanf????????
fscanf:從指定的輸入流上讀取格式化的數據
int fscanf ( FILE * stream, const char * format, ... );stream:要讀取的文件指針,可以是標準輸入流stdin、文件指針或者其他已經打開的文件流format:格式控制字符串,指定了要讀取的數據的格式和順序...:可變參數列表,用于接收讀取的數據
fscanf其功能為根據數據格式(format),從輸入流(stream)中讀入數據,存儲到...中,遇到空格和換行時結束,這與fgets有區別,fgets遇到空格不結束
int main()
{FILE* pb = fopen("text.txt", "r");//打開文件//判斷是否打開成功if (pb == NULL) {perror("fopen1");return 1;}char b = 0; char arr[10] = { 0 };//從文件流中讀取數據格式化后分別放到b和arr中fscanf(pb, "%c\n%s", &b, arr); printf("%c\n", b); printf("%s", arr);fclose(pb); pb = NULL; return 0;
}
sscanf
sscanf文檔鏈接:
????????
sscanf - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/sscanf/?kw=sscanf????????
sscanf:在字符串中讀取格式化的數據
?
int sscanf ( const char * s, const char * format, ...);str:要解析的字符串 format:格式字符串 ...:可變參數列表,用于接收解析后的數據
?返回值:函數將返回成功賦值的字段個數,失敗返回0 ,否則返回格式化的參數個數
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>int main()
{char arr[] = "kiana";char arr1[10] = { 0 };//從字符串arr中讀取數據放入arr1中sscanf(arr, "%s", arr1);printf("%s\n", arr1);int n = 0;sscanf("kiana 1134", "%s %d", arr1, &n);printf("%s %d", arr1, n);return 0;
}
sscanf的優點:
????????
sscanf函數可以根據格式字符串的規則解析不同類型的數據,具有很高的靈活性
????????
在使用sscanf函數時,要確保格式字符串與要解析的數據格式匹配,否則可能會導致解析錯誤或未定義的行為
????????
需要注意的是,sscanf函數只會從字符串中解析數據,不會對字符串進行修改
4.4?printf / sprintf / fprintf
函數 | 功能 |
---|---|
printf? ? ?? | 把數據以格式化的形式打印在標準輸出流上 |
fprintf | 把數據以格式化的形式打印在指定的輸出流上 |
sprintf | 把格式化的數據轉化成字符串 |
printf
printf文檔鏈接:
????????
printf - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/printf/?kw=printf????????
printf:把數據以格式化的形式打印在標準輸出流上
int printf ( const char * format, ... );
fprintf
fprintf文檔鏈接:
????????
fprintf - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fprintf/?kw=fprintf????????
fprintf:把數據以格式化的形式打印在指定的輸出流上
int fprintf ( FILE * stream, const char * format, ... );
函數功能:根據指定的格式(format),向輸出流(比如文件流)寫入數據
????????
返回值:如果寫入文件成功,則返回寫入的總字符數,如果寫入文件失敗,則返回負值
int main()
{FILE* pa = fopen("text.txt", "w");if (pa == NULL){perror("fopen");return 1;}char arr[] = "kiana";int a = 10;//把格式化數據輸出到文件中fprintf(pa, "%s %d", arr, a);fclose(pa);pa == NULL;return 0;
}
?sprintf
sprintf文檔鏈接:
????????
sprintf - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/sprintf/?kw=sprintf????????
sprintf:把格式化的數據轉化成字符串
int sprintf ( char * str, const char * format, ... );
函數功能是把格式化的數據寫入某個字符串中,即發送格式化輸出到 str?所指向的字符串?
返回值:
????????
如果成功,則返回寫入的字符總數,不包括字符串追加在字符串末尾的空字符
????????
如果失敗,則返回一個負數
int main()
{char arr[] = "kianachuji";int num = 20;char arr1[20] = { 0 };sprintf(arr1, "%s %d", arr, num);//把格式化的數據存放到arr1中puts(arr1);//打印arr1return 0;
}
4.5?fread和fwrite
fread
fread文檔鏈接:
????????fread - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fread/?kw=fread????????
如果我們想要讀取多行內容,就可以使用fread函數
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
函數功能:從給定輸入流stream讀取最多count個對象存儲到指針ptr指向的數組中,每個對象size個字節,該函數以二進制形式對文件進行操作,不局限于文本文件
返回值:
????????
返回成功讀取的對象個數,若出現錯誤或到達文件末尾,則可能小于count
????????
若size或count為零,則fread返回零且不進行其他動作
????????
fread不區分文件尾和錯誤,因此調用者必須用feof和ferror才能判斷發生了什么
fwrite
fwrite文檔鏈接:
????????
fwrite - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fwrite/?kw=fwrite
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
函數功能:把ptr指向的數組中的數據存儲count個size字節的數據到輸出流stream中,該函數以二進制形式對文件進行操作,不局限于文本文件
返回值:
????????
如果成功,該函數返回一個 size_t 對象,表示元素的總數,該對象是一個整型數據類型
????????
如果該數字與num參數不同,則會顯示一個錯誤
int main()
{FILE* pa = fopen("1.txt", "wb");//以輸出二進制數據打開文件int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//輸入5個整型放在文件流中fwrite(arr, sizeof(arr), 5, pa);fclose(pa);pa == NULL;FILE* pb = fopen("1.txt", "rb");//以讀取二進制數據打開文件int arr1[10] = { 0 };//從文件中讀取三個整形存儲到arr1中fread(arr1, 4, 3, pb);for (int i = 0; i < 10; i++){printf("%d", arr1[i]);}fclose(pb);pb == NULL;return 0;
}
5. 文件的隨機讀寫
文件的隨機讀寫就是我們可以指定這個文件指針指向的位置,即指向第幾個字符,然后從這個字符開始讀寫
fseek
fseek文檔鏈接:
????????
fseek - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/fseek/?kw=fseek
int fseek ( FILE * stream, long int offset, int origin );stream:文件指針 offset:相對于起始位置的偏移量origin:起始位置
函數功能:根據文件指針的位置和偏移量來定位文件指針
????????
返回值:成功返回0,失敗返回一個非零值
int main()
{FILE* pa = fopen("1.txt", "w");//寫if (pa == NULL){perror("fopen");return 1;}//把字符串輸出到文件流中fputs("abcdefgh", pa);//把光標移到起始位置向右偏移量為5的位置fseek(pa, 5, SEEK_SET);//把字符串123輸出到文件流中fputs("123", pa);fclose(pa);pa == NULL;return 0;
}
ftell
ftell文檔鏈接:
????????
ftell - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/ftell/?kw=ftell
long int ftell ( FILE * stream );
函數功能:返回文件指針相對于起始位置的偏移量
????????
返回值:成功則返回一個偏移量,失敗則返回-1
int main()
{FILE* pa = fopen("text.txt", "w");//寫if (pa == NULL){perror("fopen");return 1;}//把字符串輸出到文件流中fputs("abcdefgh", pa);//把光標移到起始位置向右偏移量為5的位置fseek(pa, 5, SEEK_SET);int a = ftell(pa);printf("%d", a);fclose(pa);pa == NULL;return 0;
}
rewind
rewind文檔鏈接:
????????
rewind - C++ Reference
https://legacy.cplusplus.com/reference/cstdio/rewind/?kw=rewind
void rewind ( FILE * stream );
函數功能:讓文件指針的位置回到文件的起始位置
int main()
{FILE* pa = fopen("1.txt", "w");//寫if (pa == NULL){perror("fopen");return 1;}//把字符串輸出到文件流中fputs("abcdefgh", pa);//把光標移到起始位置向右偏移量為5的位置fseek(pa, 5, SEEK_SET);int a = ftell(pa);printf("重置之前偏移量為%d\n", a);rewind(pa);//把文件指針重置到文件起始位置int b = ftell(pa);printf("重置之后偏移量%d", b);fclose(pa);pa == NULL;return 0;
}
6. 文件讀取結束的判定
注意:在文件讀取過程中,不能用feof函數的返回值直接來判斷文件的是否結束
?
feof 的作用是:當文件讀取結束之后,判斷是讀取結束的原因是否是遇到文件尾結束
文本文件讀取是否結束,判斷返回值是否為 EOF ( fgetc ),或者 NULL ( fgets )
????????
例如:
????????
fgetc 判斷是否為 EOF????????????????fgets 判斷返回值是否為 NULL?
文本文件舉例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{int c; // 注意:int,?char,要求處理EOFFILE* fp = fopen("1.txt", "r");if (!fp) {perror("File opening failed");return EXIT_FAILURE;}//fgetc 當讀取失敗的時候或者遇到?件結束的時候,都會返回EOFwhile ((c = fgetc(fp)) != EOF) // 標準C I/O讀取?件循環{putchar(c);}//判斷是什么原因結束的if (ferror(fp))puts("I/O error when reading");else if (feof(fp))puts("End of file reached successfully");fclose(fp);
}
二進制文件的讀取結束判斷
二進制文件的讀取結束判斷,判斷返回值是否小于實際要讀的個數,例如:
????????
fread判斷返回值是否小于實際要讀的個數,若出現錯誤或到達文件末尾,則可能小于count,write判斷返回值是否等于實際要寫入的數據個數
#include<stdio.h>int main()
{FILE* pa = fopen("1.txt", "wb");//以輸出二進制數據打開文件int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int ret = fwrite(arr, sizeof(arr), 5, pa);//輸入5個整型放在文件流中if (ret != 5)//判斷是否寫入成功{perror("fwrite");}fclose(pa);//關閉文件pa == NULL;FILE* pb = fopen("text.txt", "rb");//以讀取二進制數據打開文件int arr1[10] = { 0 };int rat = fread(arr1, 4, 3, pb);//從文件中讀取三個整形存儲到arr1中if (rat == 3)//判斷返回值是否等于size{printf("返回值等于size\n");}else//不等于的話判斷1.到達文件末尾2.讀取出錯{if (feof(pb)){printf("到達文件末尾");}elseperror("fread error");}for (int i = 0; i < 10; i++)//輸入{printf("%d", arr1[i]);}fclose(pb);pb == NULL;return 0;
}
7. 文件緩沖區
ANSIC標準采用“緩沖文件系統”處理的數據文件的,所謂緩沖?件系統是指系統自動地在內存中為 程序中每?個正在使用的文件開辟?塊“文件緩沖區”,從內存向磁盤輸出數據會先送到內存中的緩 沖區,裝滿緩沖區后才?起送到磁盤上
????????
如果從磁盤向計算機讀入數據,則從磁盤文件中讀取數據輸 入到內存緩沖區(充滿緩沖區),然后再從緩沖區逐個地將數據送到程序數據區(程序變量等)。緩 沖區的大小根據C編譯系統決定的
#include <stdio.h>
#include <windows.h>int main()
{FILE* pf = fopen("test.txt", "w");fputs("abcdef", pf);//先將代碼放在輸出緩沖區 printf("睡眠10秒-已經寫數據了,打開test.txt?件,發現?件沒有內容\n");Sleep(10000);printf("刷新緩沖區\n");fflush(pf);//刷新緩沖區時,才將輸出緩沖區的數據寫到?件(磁盤) //注:fflush 在?版本的VS上不能使?了 printf("再睡眠10秒-此時,再次打開test.txt?件,?件有內容了\n");Sleep(10000);fclose(pf);//注:fclose在關閉?件的時候,也會刷新緩沖區 pf = NULL;return 0;
}
?
?
完結撒花~
?