今日學習內容
1. 文件IO與標準IO核心對比
特性 | 標準IO | 文件IO |
---|---|---|
實現層 | C標準庫 | Linux內核系統調用 |
緩沖機制 | 全緩沖/行緩沖 | 無緩沖(實時讀寫) |
操作對象 | FILE* 流指針 | 整型文件描述符(fd) |
移植性 | 跨平臺兼容 | Linux特有 |
典型應用場景 | 普通文件操作 | 硬件設備/特殊文件操作 |
性能特點 | 減少系統調用(批量操作高效) | 實時響應(適合高頻小數據) |
2. 文件描述符(File Descriptor)
(1) 內核級文件訪問句柄
- 本質:整數標識符(索引內核文件表)
- 預定義fd:
fd 符號 設備 0 STDIN
標準輸入 1 STDOUT
標準輸出 2 STDERR
標準錯誤
(2) 生命周期管理
int fd = open("file.txt", O_RDWR); // 獲取fd
read(fd, buf, size); // 使用fd操作
close(fd); // 釋放fd(必須!)
3. 文件權限控制:umask機制
(1) 權限計算規則
權限計算遵循公式:mode & ~umask
- 查看umask:終端輸入
umask
4. 核心系統調用詳解
(1) 文件打開:open
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *pathname, int flags, mode_t mode);
參數 | 說明 |
---|---|
pathname | 文件路徑 |
flags | 打開標志 |
mode | 創建文件時的權限(僅O_CREAT時有效) |
常用flags組合:
場景 | flags組合 |
---|---|
只讀打開 | O_RDONLY |
只寫打開 | O_WRONLY |
讀寫打開 | O_RDWR |
創建文件 | O_CREAT |
追加寫入 | O_APPEND |
清空文件 | O_TRUNC |
(2) 數據讀取:read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- 返回值:
- 成功:實際讀取字節數
- 文件末尾:0
- 錯誤:-1
(3) 數據寫入:write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
- 返回值:實際寫入字節數(可能小于請求值)
(4) 文件定位:lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
whence | 定位基準 |
---|---|
SEEK_SET | 文件開頭 |
SEEK_CUR | 當前位置 |
SEEK_END | 文件末尾 |
典型應用:
lseek(fd, 0, SEEK_END); // 定位到文件末尾
(5) 文件關閉:close
#include <unistd.h>int close(int fd); // 成功返回0,失敗返回-1
打開的文件描述符必須顯式關閉!
5. 代碼
open.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);if(-1 == fd){printf("error\n");return -1;}printf("fd = %d\n", fd);close(fd);return 0;
}
????write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);if(-1 == fd){printf("error\n");return -1;}char *buf = "hello";write(1, buf, sizeof(buf));close(fd);return 0;
}
read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./2.txt", O_RDONLY);if(-1 == fd){printf("error\n");return -1;}char buff[1024] = {0};ssize_t cnt = read(fd, buff, sizeof(buff));// printf("cnt = %ld\n", cnt);printf("buff = %s\n", buff);close(fd);return 0;
}
cats
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open(argv[1], O_RDONLY);if(-1 == fd){printf("error\n");return -1;}char buff[1024] = {0};while(1){ssize_t cnt = read(fd, buff, sizeof(buff));write(1, buff, cnt);if(0 == cnt){break;}}close(fd);return 0;
}
copy.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open(argv[1], O_RDONLY);if(-1 == fd){printf("error\n");return -1;}char buff[1024] = {0};while(1){ssize_t cnt = read(fd, buff, sizeof(buff));write(1, buff, cnt);if(0 == cnt){break;}}close(fd);return 0;
}
lseek.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./1.txt", O_RDONLY);if(fd < 0){printf("error\n");return -1;}off_t len = lseek(fd, 0, SEEK_END);printf("%ld\n", len);lseek(fd, 0, SEEK_SET);close(fd);return 0;
}
rizhi.c
#include <stdio.h>
#include <time.h>
#include <unistd.h>
FILE *fp = NULL;
int init_log()
{fp = fopen("./log.txt", "a");if(NULL == fp){printf("open error\n");return -1;} return 0;
}int write_log(int level)
{time_t now = time(NULL);struct tm *pt = localtime(&now);const char *plevel = {0};switch (level) {case 2: plevel = "ERROR"; break;case 1: plevel = "WARNING"; break;case 0: plevel = "INFO"; break;}fprintf(fp, "[%d-%d-%d %d:%d:%d] [%d]:%s\n", pt->tm_year+1900, pt->tm_mon+1,pt->tm_mday,pt->tm_hour, pt->tm_min, pt->tm_sec, level, plevel);return 0;
}void unint_log()
{fclose(fp);
}int main(void)
{init_log();int i;for(i = 0; i < 100; ++i){write_log(2); write_log(0);write_log(1); }unint_log();return 0;
}
總結
- 文件IO核心價值:
- 直接內核交互 → 實時性保障
- 設備文件操作唯一途徑
- 系統調用:
操作 關鍵注意 open 正確處理O_CREAT的mode參數 read/write 循環處理部分寫入/讀取 lseek 支持負偏移(向前回溯) close 配對調用防止fd泄漏 - 嵌入式場景適配:
- 設備驅動開發必用文件IO
- 日志系統優先選無緩沖寫入(防斷電丟失)
- 敏感文件設置嚴格權限(
open(..., 0600)
)