【APUE】文件 I/O 操作
博客地址 :?http://blog.csdn.net/shulianghan/article/details/46980271
一. 文件打開關閉操作相關函數介紹
1. open 函數
(1) open 函數簡介
open 函數解析 :?
-- 函數定義 :?
#include <fcntl.h>intopen(const char *path, int oflag, ...);
-- 返回值 : 打開文件成功, 返回文件描述符; 如果失敗, 返回 -1; 返回的文件描述符是最小的未用描述符值
(2) open 函數參數簡介
參數解析 :?
--?const char *path : 要打開或者創建的文件名;
--?int oflag : 函數選項, 可以是多個常量進行 "或" 運算;
-- 第三參數 : 對于打開文件來說是用不到第三參數的, 如果需要創建文件, 則需要指定第三參數;
int oflag 參數必選常量解析 : 下面的三個常量必須只能且只能指定一個;
-- O_RDONLY : 打開的文件只能讀取, 沒有寫權限;
-- O_WRONLY : 打開的文件只能寫入, 沒有讀權限;
-- O_RDWR : 打開的文件既能讀取, 也能寫入, 有雙權限;
int oflag 參數可選常量解析 :?
-- O_APPEND : 每次寫入都追加到文件末尾;
-- O_CREATE : 如果文件不存在, 就創建, 如果有這個參數, 就需要使用第三個參數來指定創建文件時的參數;
-- O_EXCL : 指定該參數, 同時指定 O_CREATE, 文件如果存在就會報錯;
-- O_TRUNC : 如果文件存在, 并且有寫權限的前提下, 打開時會將其內容清空, 從新寫入;
-- O_NOCTTY : 如果第一個參數文件路徑指向一個終端設備, 不能將該設備作為進程的控制終端;
-- O_NONBLOCK : 如果文件路徑指向一個 FIFO, 特殊文件塊, 字符特殊文件, 同時指定該選項, 文件的IO操作設置為非阻塞模式;
int oflag 同步參數可選常量解析?:?
-- O_DSYNC : 每次 write 操作之前等待 IO 完成, 如果寫操作不影響讀取剛寫入的數據, 則不等待文件屬性被更新;
-- O_RSYNC : 讀操作時等待, 直到所有的寫操作都完成;
-- O_SYNC : 每次寫都要等待物理 IO 操作完成, 包括 write 引起的文件屬性更新; 即 數據和屬性同步更新;
2. create 函數
(1) create 函數簡介
create 函數簡介 :?
-- 函數定義 :?
#include <fcntl.h>intcreat(const char *path, mode_t mode); -- 返回值 : 返回只寫打開的文件描述符, 出錯返回 -1;
-- 等效函數 : open(path_name, O_WRONLY | O_CREATE | O_TRUNC, mode);
-- mode_t mode 參數 : 指定文件的所有者;
(2) create 函數局限性
create 局限性 :?
-- 只寫 : create 函數只能以只寫方式打開創建的文件;
-- 讀取新文件方法 : 先 create 創建只寫文件, 再調用 close 函數, 再調用 open 方法打開文件讀取文件;
-- 創建只讀文件 : open(path_name, O_RDWR | O_CREATE | O_TRUNC, mode);
3. close 函數
函數簡介 :?
-- 函數定義 :?
#include <unistd.h>intclose(int fildes);-- 作用 : 關閉文件, 并釋放 進程 加在該文件上得所有 記錄鎖;
-- 關于進程 : 進程終止時, 內核會自動關閉該進程中打開的所有文件, 很多情況下都會使用關閉進程隱式關閉文件;
二. 文件偏移操作相關函數介紹
1. lseek 函數
(1) lseek 函數簡介
lseek 函數簡介 :?
-- 函數定義 :?
#include <unistd.h>off_tlseek(int fildes, off_t offset, int whence);
-- 作用 : 顯式的為一個打開的文件設置偏移量;
-- 返回值 : 如果設置偏移量成功, 返回新的偏移量;
(2) 文件偏移量簡介
文件偏移量 : ?
-- 當前文件偏移量 : 每個打開的文件都有一個當前文件偏移量, 非負整數, 從開始處計算的字節數; 讀寫操作都是從當前文件偏移處開始, 讀寫會使當前文件偏移量增加 讀寫的字節數;-- 默認偏移量 : 打開一個文件時默認 當前文件偏移量 是0, 除非指定 O_APPEND 選項;
-- 偏移量的值 : 普通文件偏移量必須是非負整數; 對于某些設備文件允許存在負數偏移量, 因此判斷是否可 lseek 時, 要判斷返回的文件偏移量是否 == -1;
(3) int where 參數簡介
where 參數簡介 :?
-- SEEK_SET : 將文件偏移量設置為 0 + offset;
-- SEEK_CUR : 將文件偏移量設置為 當前位移 + offset;
-- SEEK_END : 將文件偏移量設置為 文件長度 + offset;
(4) lseek 源碼示例
源碼示例 :?
/*************************************************************************> File Name: fun_lseek.c> Author: octopus> Mail: octopus_truth.163.com > Created Time: 三 7/22 07:46:59 2015************************************************************************/#include<stdio.h> #include<unistd.h> #include<stdlib.h>int main(int argc, char * argv[]) {/** 設置標準輸入文件的 "當前文件偏移量", * 設置為當前的位置 + 0;*/if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)printf("lseek 結果 -1, 該文件不能lseek\n");elseprintf("該文件可以執行 lseek 方法\n");exit(0); }
編譯執行 :?
localhost:file octopus$ gcc fun_lseek.c localhost:file octopus$ ./a.out 該文件可以執行 lseek 方法
(5) 文件空洞
文件空洞形成 :?
-- 文件偏移量作用 : 文件偏移量是記錄在內核中, 不引起 IO 操作, 這個偏移量主要用于執行下一次的 IO 操作;
-- 空洞形成 : 如果文件偏移量大于當前文件長度, 下一次寫操作會直接加長文件, 并在中間形成一個 "文件空洞";
-- 磁盤占用情況 : 文件空洞是不占用磁盤存儲區的, 寫入數據超出文件長度時, 新寫入的數據會重新分配磁盤塊, 之間的一段文件空洞不會占用磁盤空間;
三. 文件讀寫操作相關函數介紹
1. read 函數
函數簡介 :?
-- 函數內容 :?
#include <sys/types.h>#include <sys/uio.h>#include <unistd.h>ssize_tread(int fildes, void *buf, size_t nbyte);-- 作用 : 從 fildes 代表的文件中, 讀取 nbyte 個函數到 buf 緩沖區中, 讀取到得字節數可能少于 nbyte;-- 返回值 : 如果 read 操作成功, 返回讀取到得字節數, 如果失敗, 返回 -1;
2. write 函數
函數簡介 :?
-- 函數內容 :?
#include <unistd.h>ssize_twrite(int fildes, const void *buf, size_t nbyte);
-- 函數作用 : 將 buf 字符串的前 nbyte 個字節數據寫入 files 文件標示符 代表的文件中;
-- 返回值 : 若成功, 返回已寫的字節數, 如果失敗返回 -1;
3. write read 函數示例
源碼示例 :?
-- 源碼 :?
/*************************************************************************> File Name: fun_read_write.c> Author: Han Shuliang> Mail: octopus_truth@163.com> Created Time: 五 7/29 15:00:18 2016************************************************************************/ #include <stdio.h> #include <unistd.h>#define SIZE 1024int main(int argc, char * argv[]) {int n;char buf[SIZE];//讀取標準輸入流中的數據到 buf 字節數組中while ((n = read(STDIN_FILENO, buf, SIZE)) > 0)//將 buf 字節數組中的數據寫出到 標準輸出流中if(write(STDOUT_FILENO, buf, n)!= n)printf("寫出內容出錯");if(n < 0)printf("讀取過程出錯");return 0; }
-- 執行結果 :?
bogon:file octopus$ gcc fun_read_write.c bogon:file octopus$ ./a.out Han Shuliang Han ShuliangCSDN CSDN^C bogon:file octopus$
4. 函數綜合示例
/*************************************************************************> File Name: fun_read.c> Author: octopus> Mail: octopus_truth.163.com > Created Time: 一 7/27 07:09:36 2015************************************************************************/#include <stdio.h> #include <sys/types.h> // ... read() 頭文件 #include <sys/uio.h> // ... read() 頭文件 #include <unistd.h> // ... read() write() 函數頭文件 #include <stdarg.h> // va_list 可變參數操作頭文件 #include <string.h> // strlen strcat 方法的頭文件 #include <errno.h> // errno 的頭文件 #include <stdlib.h> // exit() 方法的頭文件 #include <fcntl.h> // open() 函數的頭文件#define MAXLINE 4096 #define MAXWORD 20void err_sys(const char *fmt, ...);int main(int argc, char * argv[]) {char *buf = "abcdefg\n";char buf_read[MAXWORD];int fd;int creat_result;int write_size;int close_result;int read_size;//創建一個文件, 使用打開方式, 如果文件不存在, 就重創建并打開if( ( fd = open("file_read_write.file", O_WRONLY | O_CREAT | O_TRUNC) ) == -1)err_sys("創建文件出錯");//向文件中寫出數據if( (write_size = write(fd, buf, strlen(buf))) == -1)err_sys("向文件寫出數據出錯");if( (close_result = close(fd)) == -1)err_sys("關閉文件出錯");if( (fd = open("file_read_write.file", O_RDONLY)) == -1)err_sys("打開文件出錯");//從文件中讀取文件內容if( (read_size = read(fd, buf_read, strlen(buf)) ) == -1)err_sys("讀取文件出錯");if( (close_result = close(fd)) == -1)err_sys("關閉文件出錯");printf("文件中得內容 : %s \n", buf_read); }static void err_doit(int errnoflag, int error, const char* fmt, va_list ap) {char buf[MAXLINE];//將 ap 可變參數使用 fmt 格式, 放置 MAXLINE 個字符到 buf 緩沖中vsnprintf(buf, MAXLINE, fmt, ap);/** 如果需要錯誤信息, 根據錯誤號獲取標準錯誤信息, 將該信息添加到 buf 緩沖中* strlen 作用 : 獲取字符串長度* strerror 作用 : 根據錯誤號獲取錯誤信息*/if(errnoflag)snprintf(buf + strlen(buf), MAXLINE - strlen(buf), ": %s", strerror(errno));//在 buf 字符串后添加換行符號strcat(buf, "\n");//刷新標準輸出流fflush(stdout);//將標準錯誤輸出添加到 buf 緩沖區中fputs(buf, stderr);//刷新所有緩沖區fflush(NULL); }void err_sys(const char *fmt, ...) {va_list ap;va_start(ap, fmt);err_doit(1, errno, fmt, ap);va_end(ap);exit(0); }
執行結果 :?
octopus-2:file octopus$ ls fun_lseek.c fun_lseek_hole.c fun_read_write.c octopus-2:file octopus$ gcc fun_read_write.c octopus-2:file octopus$ sudo ./a.out Password: 文件中得內容 : abcdefgoctopus-2:file octopus$ ls a.out file_read_write.file fun_lseek.c fun_lseek_hole.c fun_read_write.c octopus-2:file octopus$
四. 文件讀寫原子操作相關函數介紹
1. pread 函數
pread 函數 :?
-- 1. 函數內容 :
#include <unistd.h> ssize_t pread(int fd, void *buf, size_t count, off_t offset);
?
-- 2. 函數作用 : 讀取文件描述符 fd 對應的文件, 返回讀取到的文件字節個數, 讀取到文件結尾 返回 0, 出現錯誤返回 -1;
-- 3. 函數返回值 : 返回讀取文件的字節數, 讀取到結尾返回 0, 出錯返回 -1;
pread 與 read 方法作用 :?
-- 1. 等價執行流程 : pread 方法等價于 先調用?lseek 方法, ?再調用?read 方法;
-- 2. 與等價流程的區別 : ① 執行 pread 方法時, 先定位 后 讀取 的兩個操作, 不能中斷; ② 文件指針 不更新;
2. pwrite?函數
pwrite?函數 :?
-- 1. 函數內容 :?
#include <unistd.h>ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
-- 2. 函數作用 : 寫出數據到指定的位置;
-- 3. 函數返回值 : 返回寫出的字節數, 出現錯誤返回 -1;
-- 4. 等價操作 : pwrite 等價于 lseek 和 write 操作;
3. pread 和 pwrite 函數示例
函數示例過程 :?
-- 1. 打開文件, 如果沒有就創建;
-- 2. 寫出 a ~ z 26個子母;
-- 3. 讀取文件?10 ~ 15 個字節;
-- 4. 向第 10 個字節處寫出 "00000" 字符串;
函數示例 :?
-- 代碼 :?
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h>int main(int argc, char **argv) {printf("main : \n");int file_fd, write_result;char * buffer = "abcdefghigklmnopqrstuvwxyz";file_fd = open("5.pread_write.txt", O_RDWR | O_APPEND | O_CREAT);printf("file_fd = %d\n", file_fd);write_result = write(file_fd, buffer, strlen(buffer));printf("write success, count = %d\n", write_result);return 0; }
.
.
.
.
.
.
博客地址 :?http://blog.csdn.net/shulianghan/article/details/46980271
總結
以上是生活随笔為你收集整理的【APUE】文件 I/O 操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【OpenGL ES】 Android
- 下一篇: 【Android应用开发】Android