網站首頁 編程語言 正文
一、文件和流
1、程序文件
包括源程序文件(后綴為.c)
目標文件(windows環境后綴為.obj)
可執行程序(windows環境 后綴為.exe)
2、數據文件
文件的內容不一定是程序,而是程序運行時讀寫的數據,比如程序運行需要從中讀取數據的文件, 或者輸出內容的文件。
3、流
任何一個C程序,運行起來就會默認打開3個流
1、FILE* stdin(標準輸入流,鍵盤)
2、FILE* stdout(標準輸出流,顯示器)
3、FILE* stderr(標準錯誤流,顯示器)
流可以理解為輸入/輸出緩沖區
二、文件組成
每個被使用的文件都在內存中開辟了一個相應的文件信息區,用來存放文件的相關信息(如文件的名 字,文件狀態及文件當前的位置等)。這些信息是保存在一個結構體變量中的。該結構體類型是由系統聲明的,取名FILE
FILE*就是文件指針類型,可以通過文件指針找到它指向的文件信息區(FILE類型的結構體),文件信息區用于維護一個文件(每個文件都是獨立的文件信息區)
三、文件的打開和關閉
1、文件的打開fopen
filename是文件名
mode是文件打開方式
文件打開方式 | 含義 | 如果指定文件不存在 |
“r”(只讀) | 為了輸入數據,打開一個已經存在的文本文件 | 出錯 |
“w”(只寫) | 為了輸出數據,打開一個文本文件 | 建立一個新的文件 |
“a”(追加) | 向文本文件尾添加數據 | 建立一個新的文件 |
“rb”(只讀) | 為了輸入數據,打開一個二進制文件 | 出錯 |
“wb”(只寫) | 為了輸出數據,打開一個二進制文件 | 建立一個新的文件 |
“ab”(追加) | 向一個二進制文件尾添加數據 | 出錯 |
“r+”(讀寫) | 為了讀和寫,打開一個文本文件 | 出錯 |
“w+”(讀寫) | 為了讀和寫,新建一個文本文件 | 建立一個新的文件 |
“a+”(讀寫) | 打開一個文件,在文件尾進行讀寫 | 建立一個新的文件 |
“rb+”(讀寫) | 為了讀和寫打開一個二進制文件 | 出錯 |
“wb+”(讀寫) | 為了讀和寫,新建一個新的二進制文件 | 建立一個新的文件 |
“ab+”(讀寫) | 打開一個二進制文件,在文件尾進行讀和寫 | 建立一個新的文件 |
2、文件關閉fclose
stream是文件指針,文件使用完后一定要fclose關閉,并把文件指針置空。(用起來像free)
int main()
{
FILE* pf = fopen("text.txt", "r");//文件路徑可以是相對路徑或絕對路徑
if (pf == NULL)
{
printf("%s\n", strerror(errno));
exit(-1);
}
fclose(pf);//不關閉文件可能會造成數據丟失
pf = NULL;
return 0;
}
四、文件的順序讀寫
字符輸入函數 | fgetc | 所有輸入流 |
字符輸出函數 | fputc | 所有輸出流 |
文本行輸入函數 | fgets | 所有輸入流 |
文本行輸出函數 | fputs | 所有輸出流 |
格式化輸入函數 | fscanf | 所有輸入流 |
格式化輸出函數 | fprintf | 所有輸出流 |
二進制輸入 | fread | 文件 |
二進制輸出 | fread | 文件 |
1、使用fputc和fgetc寫入/讀取單個字符
寫入單個字符到文件
character:要寫入的字符
stream:指向輸出流 FILE 對象的指針。
int main()
{
FILE* pf = fopen("text.txt", "w");//文件路徑可以是相對路徑或絕對路徑
if (pf == NULL)
{
printf("%s\n", strerror(errno));
//perror("fopen");//void perror ( const char * str )用來將上一個函數發生錯誤的原因輸出到標準設備(stderr)
exit(-1);
}
for (char i = 'a'; i <= 'z'; i++)
{
fputc(i, pf);//輸出
}
fclose(pf);
pf = NULL;
}
讀取文件中的單個字符
stream:指向輸入流 FILE 對象的指針。
int main()
{
pf = fopen("text.txt", "r");//文件路徑可以是相對路徑或絕對路徑
if (pf == NULL)
{
printf("%s\n", strerror(errno));
exit(-1);
}
printf("%c\n", fgetc(pf));//輸入,也可以寫一個循環讀取
printf("%c\n", fgetc(pf));
printf("%c\n", fgetc(pf));
printf("%c\n", fgetc(pf));
printf("%c\n", fgetc(pf));
fclose(pf);
pf = NULL;
return 0;
}
2、使用fputs和fgets寫入/讀取一串字符
寫入一串字符到文件
str:要寫入的字符串的地址
stream:指向輸出流 FILE 對象的指針。
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
char arr[] = "abcde";//text.txt文件被寫入abcde
fputs(arr, pf);
fclose(pf);
pf = NULL;
return 0;
}
讀取文件中num個字符
str:讀到的字符串放到str指向的空間里去
num:讀取的字符串個數
stream:指向輸入流 FILE 對象的指針。
讀取成功:返回str的地址
讀取失敗或錯誤:返回空指針
監視發現,我們從文件中讀取5個字符,實際只讀了4個,最后一個補了\0
3、使用fprintf和fscanf按照指定的格式寫入/讀取
stream:指向輸出流 FILE 對象的指針。
后續參數使用方法與printf一樣
struct S
{
char name[20];
int tele;
float scores;
};
int main()
{
struct S s = { "zhangsan",1510,66.5f };
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
fprintf(pf, "%s %d %f", s.name, s.tele, s.scores);//打印到txt文件
fprintf(stdout, "%s %d %f", s.name, s.tele, s.scores);//打印到屏幕
fclose(pf);
pf = NULL;
return 0;
}
stream:指向輸入流 FILE 對象的指針。
后續參數使用方法和scanf一樣
struct S
{
char name[20];
int tele;
float scores;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
fscanf(pf, "%s %d %f", s.name, &s.tele, &s.scores);//將文件中的內容讀取到結構體中
printf("%s %d %f", s.name, s.tele, s.scores);
fclose(pf);
pf = NULL;
return 0;
}
4、使用fwrite和fread按照二進制的方式寫入/讀取
ptr:從ptr指向的當前位置開始寫入
size:每個元素的大小
count:要寫入的元素個數
stream:指向輸出流 FILE 對象的指針。
struct S
{
char name[20];
int tele;
float scores;
};
int main()
{
struct S s = { "zhangsan",1510,66.5f };
FILE* pf = fopen("text.txt", "wb");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
fwrite(&s, sizeof(struct S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
fread參數和fwrite一樣
ptr:從ptr指向的當前位置開始讀取
struct S
{
char name[20];
int tele;
float scores;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("text.txt", "rb");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
fread(&s, sizeof(struct S), 1, pf);
printf("%s %d %f", s.name, s.tele, s.scores);
fclose(pf);
pf = NULL;
return 0;
}
5、使用sprintf和sscanf將格式化數據和字符串互相轉換(文件無關)
將格式化數據轉換為字符串
str:將格式化數據放到目標地址
后續參數和使用方式和printf一樣
struct S
{
char name[20];
int tele;
float scores;
};
int main()
{
struct S s = { "zhangsan",1510,66.5f };
char arr[60]={0};
sprintf(arr, "%s %d %f", s.name, s.tele, s.scores);
printf("%s", arr);
return 0;
}
將字符串轉換為格式化數據
s:指向字符串的指針
后續參數和使用方式和scanf一樣
struct S
{
char name[20];
int tele;
float scores;
};
int main()
{
struct S s = { 0 };
char arr[60]={ "zhangsan 1510 66.5f" };
sscanf(arr, "%s %d %f", s.name, &s.tele,&s.scores);
printf("%s %d %f", s.name,s.tele,s.scores );
return 0;
}
五、文件的隨機讀寫
1、fseek(指定文件指針的位置)
注意:每次文件讀取完畢后,文件指針++
stream:指向標識流的 FILE 對象的指針
offset:指針偏移量
origin:指針起始點,如下圖:
SEEK_SET | 文件開頭 |
SEEK_CUR | 文件指針的當前所處的位置 |
SEEK_END | 文件結尾 |
int main()
{
FILE* pf = fopen("text.txt", "r+");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
fputs("abcde", pf);
fseek(pf, 2, SEEK_SET);
int ch = fgetc(pf);//該語句執行完畢后,指針++,指向d
printf("%c ", ch);//打印c
fseek(pf, 0, SEEK_CUR);
ch = fgetc(pf); //該語句執行完畢后,指針++,指向e
printf("%c ", ch);//打印d
fseek(pf, -1, SEEK_END);//這里SEEK_END是指向e的后一個
ch = fgetc(pf);//該語句執行完畢后,指針++,指向e的后一個
printf("%c ", ch);//打印e
fclose(pf);
pf = NULL;
return 0;
}
2、ftell(求文件指針與起始位置的偏移量)
int main()
{
FILE* pf = fopen("text.txt", "r+");
if (pf == NULL)
{
perror("fopen:");
exit(-1);
}
fputs("abcde", pf);
fseek(pf, -1, SEEK_END);//這里SEEK_END是指向e的后一個
int ch = fgetc(pf);//該語句執行完畢后,指針++,指向e的后一個
printf("%c ", ch);//打印e
printf("%d", ftell(pf));//打印5,當前指針在e的后一個,相對于a相差5
fclose(pf);
pf = NULL;
return 0;
}
3、rewind(讓文件指針回到起始位置)
六、文本文件和二進制文件的區別
數據在內存中以二進制的形式存儲,如果不加轉換的輸出到外存,就是二進制文件。
如果要求在外存上以ASCII碼的形式存儲,則需要在存儲前轉換。以ASCII字符的形式存儲的文件就是文本文件。 字符一律以ASCII形式存儲,數值型數據既可以用ASCII形式存儲,也可以使用二進制形式存儲。
七、文件讀取結束的標志
文本文件讀取是否結束,fgetc判斷返回值是否為 EOF . fgets判斷返回值是否為 NULL
二進制文件的讀取結束判斷,判斷返回值是否小于實際要讀的個數。 例如: fread判斷返回值是否小于還是等于實際要讀的個數。
feof:判斷文件是否讀到末尾而結束,返回值為真,就是讀到了文件結束
ferror:判斷文件是否讀取錯誤而結束,返回值為真,就是文件讀取遇到了錯誤
八、文件緩沖區
ANSIC 標準采用“緩沖文件系統”處理的數據文件的,所謂緩沖文件系統是指系統自動地在內存中為程序中每一個正在使用的文件開辟一塊“文件緩沖區”。
從內存向磁盤輸出數據會先送到內存中的緩沖區,裝滿緩沖區后才一起送到磁盤上。
如果從磁盤向計算機讀入數據,則從磁盤文件中讀取數據輸入到內存緩沖區(充滿緩沖區),然后再從緩沖區逐個地將數據送到程序數據區(程序變量等)。緩沖區的大小根據C編譯系統決定的。
原文鏈接:https://blog.csdn.net/gfdxx/article/details/125884458
相關推薦
- 2022-03-11 CentOS?8安裝Docker的詳細教程_docker
- 2023-05-03 C++類與對象的基礎知識點詳細分析_C 語言
- 2023-01-23 Kotlin泛型的型變之路演變示例詳解_Android
- 2022-04-09 一起來學習一下python的數據類型_python
- 2022-03-24 Android使用Span打造豐富多彩的文本詳解_Android
- 2022-03-15 request doesn‘t contain a multipart/form-data or m
- 2022-08-19 python?GUI多行輸入文本Text的實現_python
- 2022-01-09 ng-zorro中樹(nz-tree)的拖拽
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支