C語言中的文件操作
- 在C語言中霎肯,文件是存儲一連串bytes的數(shù)據(jù)翔试,可以被當(dāng)作文本或者位串來處理
- 文件也是一種輸入輸出流,被定義在
stdio.h
中的FILE
類型變量 -
FILE *myFile
指針指向文件的起始位置 -
EOF
是定義在頭文件stdio.h
中的常量基矮,值取決于具體實現(xiàn)(通常為-1
)聚磺,在操作系統(tǒng)中:Ctrl-Z
(Windows熱鍵)Control-D
(macOS熱鍵)
1. 打開文件
FILE * fopen(const char * path, const char * mode);
path:標(biāo)示文件名string字面量
mode:表示訪問模式的string字面量
-
讀取模式(const char * mode)
| mode | 介紹 |
| --- | --- |
| “r” | 讀取 |
| “w” | 寫入(如果文件不存在則創(chuàng)建新的文件,如果文件已經(jīng)存在就把文件清空)|
| “a” | 添加(如果文件不存在則創(chuàng)建新的文件) |
| “r+” | 打開一個已經(jīng)存在的文件進行讀寫 |
| “w+” | 打開文件進行讀寫(如果文件已經(jīng)存在把文件清空聂沙,不存在創(chuàng)建新的) |
| “a+” | 打開文件進行讀寫(如果文件已經(jīng)存在秆麸,從已有文件開頭開始讀,從已有文件結(jié)尾開始寫入及汉;若不存在則創(chuàng)建新的文件) |
(二進制讀取模式:"rb"
,"wb"
,"ab"
,"rb+"
,"wb+"
,"ab+“
) 注意在C語言中沮趣,文件改變沒有任何確認
如果失敗返回NULL,可能讀取失敗或者到了EOF(使用文件狀態(tài)函數(shù)來判斷)
2. 讀寫文件
2.1 讀寫單個字符:getc / putc
getc:
int getc(FILE *infp);
- 與用于
stdin
的getchar
函數(shù)相似 - 獲得文件指針指向文件位置的下一個字符
- 如果下一個字符不存在返回
EOF
putc:
int putc(int c, FILE *outfp);
- 與用于
stdout
的putchar
函數(shù)相似 - 將
c
寫入文件指針指向文件位置的下一個字符 - 成功返回
c
的int值坷随,失敗返回EOF
2.2 讀寫字符串:fgets / fputs
fgets:
char * fgets(char *s, int max, FILE *fp)
- 從fp指向的輸入流中讀取房铭,直到文件中出現(xiàn)
\n
驻龟,\n
也會讀入到文件中(并自動在\n
后添加\0
) - s必須保證有足夠的大小去容納輸入的字符串(包括自動添加在結(jié)尾的
\0
) - 如果讀取的長度大于
max-1
,最多有max-1
個字符會被讀取缸匪,第max個字符為\0
- 如果讀取失敗或者讀到
EOF
返回NULL
- stdout會在調(diào)用該函數(shù)后自動刷新
fputs:
int fputs(char *s, FILE *fp)
- 將s指向的字符串寫入到fp指向的流中
- s必須以
’\0’
結(jié)尾 - 如果成功返回0翁狐,失敗返回EOF
2.3 格式化讀寫:fscanf / fprintf
fscanf:
int fscanf(FILE * stream, const char * format, [argument...]);
-
stream
:輸入流,可傳入指向讀取文件的指針凌蔬,如果在此傳入stdin
露懒,那么等價scanf
(C語言將文件和輸入輸出設(shè)備等價) - 根據(jù)指定的格式(format)向輸出流(stream)寫入數(shù)據(jù)(argument)
- 成功就返回讀取到的字符個數(shù),失敗返回EOF
fprintf:
int fprintf(FILE *stream, const char *format, [ argument ]...)
- 根據(jù)指定的格式向輸出流寫入數(shù)據(jù)
-
stream
:輸出流砂心,指向讀取文件的指針隐锭,如果在此傳入stdout
,那么等價printf(C語言將文件和輸入輸出設(shè)備等價) - 成功就返回寫入到文件的字符個數(shù)计贰,失敗返回一個負數(shù)
2.4 按字節(jié)讀寫:fread / fwrite / fseek
fread:
size_t fread(void *buffer, size_t size, size_t count, FILE *stream) ;
- 從文件流中讀數(shù)據(jù)钦睡,最多讀取
count
個項,每個項size
個字節(jié) - 如果調(diào)用成功返回實際讀取到的項個數(shù)(小于或等于
count
)躁倒,如果不成功或讀到EOF
返回0
fwrite:
size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream);
- 向指定的流中寫入
count
個數(shù)據(jù)荞怒,每個項size
個字節(jié) - 成功執(zhí)行則返回實際寫入的數(shù)據(jù)個數(shù)
fseek:
int fseek(FILE *stream, long offset, int fromwhere);
- 設(shè)置文件指針
stream
的位置 -
stream
將指向以fromwhere
為基準,偏移offset
(指針偏移量)個字節(jié)的位置 - fromwhere取值:
0 / SEEK_SET:文件開頭
1 / SEEK_CUR:當(dāng)前位置
2 / SEEK_END:文件結(jié)尾
- 執(zhí)行成功返回
0
秧秉,如果執(zhí)行失敗(比如offset
取值大于等于2*1024*1024*1024褐桌,即long的正數(shù)范圍),則不改變stream指向的位置象迎,函數(shù)返回一個非0值
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
FILE *fp;
char c[] = "this is tutorialspoint";
char buffer[100];
/* w+模式打開文件 */
fp = fopen("file.txt", "w+");
/* 將字符串寫入文件 */
fwrite(c, strlen(c) + 1, 1, fp);
/* 設(shè)置指針至文件開頭 */
fseek(fp, 0, SEEK_SET);
/* 讀取并顯示數(shù)據(jù) */
fread(buffer, strlen(c) + 1, 1, fp);
printf("%s\n", buffer);
fclose(fp);
return(0);
}
輸出:
this is tutorialspoint
3. 關(guān)閉文件
int fclose( FILE *myFile );
- 將緩存中還未處理的數(shù)據(jù)全部排出至文件
- 關(guān)閉文件荧嵌,釋放該文件使用的內(nèi)存
- 成功返回
0
,失敗返回EOF
4. 其他文件方法
int getw(FILE *fp)
- 從fp所指向流讀取下一個整型值
int putw(int w, FILE *fp);
- 往fp指向的流中寫入一個整型值
long ftell(FILE *stream)
- 得到文件位置指針當(dāng)前位置相對于文件首的偏移字節(jié)數(shù)
void rewind(FILE *stream)
- 將文件內(nèi)部的位置指針重新指向一個流(數(shù)據(jù)流/文件)的開頭
5. 判斷文件狀態(tài)
注意??:可在fgets等函數(shù)返回NULL時用文件狀態(tài)函數(shù)判斷時讀取發(fā)生了錯誤還是遇到了EOF
int ferror(FILE *fp)
- 檢查錯誤砾淌,如果在讀取時發(fā)生錯誤返回一個非0值啦撮,反之返回0
int feof(FILE *fp)
- 檢查是否已經(jīng)到達文件末尾,如果文件結(jié)束返回一個非0值汪厨,反之返回0
6. 緩存(Buffer)
- 因為處理器和輸入輸出設(shè)備的速度上有很大的差距赃春,所以在中間添加了緩存減少同步時間上的延遲
- 當(dāng)輸入輸出時,數(shù)據(jù)首先存儲在緩存里(并不會調(diào)用函數(shù)后馬上輸入輸出到流上
- 緩存填滿的時候才會輸入/輸出到設(shè)備(或者讀取到
’/n’
)
image
強制刷新緩存:fflush
//顯示器
fflush(stdout);
//文件
fflush(outfile);
7. 計算文件大小
#include<stdio.h>
void main(){
FILE *fp;
char ch;
int size = 0;
fp = fopen("MyFile.txt", "r");
if (fp == NULL){
printf("文件打開失敗");
}
/* 將指針移至文件末尾 */
fseek(fp, 0, 2);
/* 獲取末尾位置的偏移量 */
size = ftell(fp);
printf("文件大小為: %d\n", size);
fclose(fp);
}
8. 拷貝文件內(nèi)容
#include<stdio.h>
void main(){
FILE *fp1, *fp2;
char ch;
int pos;
if ((fp1 = fopen("File_1.txt","r")) == NULL){
printf("文件打開失敗");
return;
}
fp2 = fopen("File_2.txt", "w");
//將指向文件fp1的指針指向fp1末尾
fseek(fp1, 0L, SEEK_END);
//計算文件fp1的長度
pos = ftell(fp1);
//將指向文件fp1的指針指會fp1開頭
fseek(fp1, 0L, SEEK_SET);
while (pos--){
//逐個字符拷貝
ch = fgetc(fp1);
fputc(ch, fp2);
}
fcloseall();
}
9. 逆轉(zhuǎn)文件內(nèi)容
#include<stdio.h>
#include<errno.h>
//計算原文件長度
long count_characters(FILE *);
void main(){
int I;
long cnt;
char ch, ch1;
FILE *fp1, *fp2;
if (fp1 = fopen("File_1.txt", "r")) {
fp2 = fopen("File_2.txt", "w");
cnt = count_characters(fp1);
/*
將fp1指針指向文件的最后一位字符
*/
fseek(fp1, -1L, SEEK_END);
printf("拷貝字符長度: %d\n", ftell(fp1));
while (cnt){
ch = fgetc(fp1);
fputc(ch, fp2);
//為什么這里移動的是兩個劫乱?
fseek(fp1, -2L, SEEK_CUR);
cnt--;
}
printf("反轉(zhuǎn)拷貝成功");
}else{
perror("Error occured\n");
}
fclose(fp1);
fclose(fp2);
}
/*
計算文件的長度
*/
long count_characters(FILE *f) {
fseek(f, -1L, 2);
long last_pos = ftell(f);
last_pos++;
return last_pos;
}