一、概念
????????標準IO是有緩存的IO,文件IO沒有緩存,適合于通信、硬件設備操作
????????標準IO是庫函數,文件IO是系統調用
文件 IO 與標準 IO(基于 C 庫函數的 IO)是 Linux 中兩種主要的 IO 方式,二者的核心差異如下:
特性 | 文件 IO(系統調用) | 標準 IO(庫函數) |
---|---|---|
緩存機制 | 無用戶空間緩存,依賴內核緩存 | 有用戶空間緩存(全緩存、行緩存等) |
接口類型 | 系統調用(如 open、read、write) | 庫函數(如 fopen、fread、fwrite) |
效率 | 頻繁調用時效率較低(系統調用開銷) | 效率高(緩存減少系統調用次數) |
實時性 | 實時性好(直接與內核交互) | 實時性差(緩存延遲刷新) |
適用場景 | 底層開發、實時性要求高的場景 | 普通文件操作、追求開發效率的場景 |
二、系統調用與庫函數
????????系統調用:是Linux內核中的代碼,只能在Linux系統中使用
????????庫函數:是對系統調用的封裝,可以在不同的操作系統中安裝并使用,庫函數最終還是要調用系統調用完成對應功能
三、文件IO函數接口
1. 函數接口:
標準IO ????????????????文件IO
fopen???????? ????????open
fclose ????????????????close
fgetc/fputc ????????read/write
fgets/fputs
fscanf/fprintf
fread/fwrite
fseek/ftell/rewind???????? lseek
2. 文件打開
原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:
打開文件,獲得操作文件的?文件描述符
參數:
pathname
:要打開的文件路徑flags
:打開文件的標志(必須包含?O_RDONLY
/O_WRONLY
/O_RDWR
?三者之一,可選輔助標志如下):O_RDONLY
:只讀O_WRONLY
:只寫O_RDWR
:讀寫O_CREAT
:文件不存在時創建(需配合?mode
?指定文件權限)O_TRUNC
:文件存在時,截斷為 0(清空內容)O_APPEND
:寫操作時追加到文件末尾O_EXCL
:與?O_CREAT
?配合,若文件已存在則報錯
返回值:
- 成功:返回?新文件描述符(非負整數)
- 失敗:返回?
-1
注意:
- 有三個特殊的文件描述符:
- 標準輸入:
0
- 標準輸出:
1
- 標準錯誤:
2
- 標準輸入:
- 文件描述符特點:
- 是?非負整數;
- 取值為?尚未被占用的最小非負整數;
- 存在上限,到達上限后再打開文件會報錯。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>int main(void)
{int fd = 0;// // close(0); //關閉輸入流// getchar();// // close(1);// printf("hello");//0664 //八進制//110110100//rw-rw-r--//O_WRONLY: 00000001// O_CREAT: 00000100// O_TRUNC: 00001000// -------------------- |// flags: 00001101 // 所有標志位被合并起來fd = open("a.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);printf("fd = %d\n",fd); //[文件描述符]fd = 3 (從3開始)//0,1,2 被占用(有上限)if(-1 == fd){perror("fail to open");return -1;}//rfd = open("a.txt",O_RDONLY,0664);//r+fd = open("a.txt",O_RDWR,0664);//Wfd = open("a.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);//w+fd = open("a.txt",O_RDWR | O_CREAT | O_TRUNC,0664);//afd = open("a.txt",O_WRONLY | O_APPEND | O_CREAT,0664);//a+fd = open("a.txt",O_RDWR | O_APPEND | O_CREAT,0664);close(fd);return 0;
}
3. 關閉文件描述符
原型:
int close(int fd);
功能:
關閉文件描述符
4. 標準 I/O 對應的文件 I/O 的打開方式
標準 I/O | 文件 I/O 打開方式 | ||
---|---|---|---|
r | O_RDONLY | ||
r+ | O_RDWR | ||
w | `O_WRONLY | O_CREAT | O_TRUNC, 0664` |
w+ | `O_RDWR | O_CREAT | O_TRUNC, 0664` |
a | `O_WRONLY | O_APPEND | O_CREAT, 0664` |
a+ | `O_RDWR | O_APPEND | O_CREAT, 0664` |
5. 文件 I/O 讀寫
1. write
原型:
ssize_t write(int fd, const void *buf, size_t count);
功能:
向文件描述符?fd
?中,寫入?buf
?指向的?count
?個字節?的數據
參數:
fd
:文件描述符buf
:要寫入的數據空間?首地址count
:要寫入的?字節數
返回值:
- 成功:返回?實際寫入的字節數
- 失敗:返回?
-1
四、實戰練習
//圖片拷貝#include<stdio.h>
#include<string.h>int main(void)
{FILE *fp1 = NULL;FILE *fp2 = NULL;size_t nret = 0;char pic[4096] = {0};fp1 = fopen("pp1.png","r");fp2 = fopen("dst.png","w");if(fp1 == NULL || fp2 == NULL){perror("fail to fopen");return -1;}while(1){nret = fread(pic,1,sizeof(pic),fp1);if(nret == 0){break;}fwrite(pic,1,nret,fp2);// fwrite(pic,nret,1,fp2);}fclose(fp1);fclose(fp2);return 0;
}
//2. 統計一個文件中出現最多的字符是哪個?出現了多少次?// + 使用鏈表實現// + 使用數組實現// 0 - 255 cnt[256]// 'a' -> cnt[97]#include<stdio.h>
#include<string.h>int main(void)
{FILE *fp = NULL;char file[256] = {0};int ch[256] = {0};int i = 0;printf("請輸入文件的名字:\n");fgets(file,sizeof(file),stdin);file[strlen(file)-1] = '\0';fp = fopen(file,"r");if(NULL == fp){perror("fail to fopen");return -1;}while(1){i = fgetc(fp);if(EOF == i){break;}ch[i]++;}fclose(fp);int max = 0;for(i = 0;i < 256;i++){if(ch[i] > ch[max]){max = i;}}for(i = 0;i < 256;i++){if(ch[i] == ch[max]){printf("文件中出現最多的字符是'%c'\n",(char)i); printf("其ascii碼值為: %d\n",i);printf("出現了%d次\n",ch[i]);} }return 0;
}