做棋牌網站建設哪家便宜免費數據查詢網站
目錄
預備知識
復習C文件IO相關操作
printf相關函數
fprintf
snprintf
讀取文件
系統(tǒng)文件IO操作
open函數
umask()函數
open函數返回值
預備知識
1.你真的理解文件原理和操作了嗎?不是語言問題,是系統(tǒng)問題
2.是不是只有C/C++有文件操作呢? 不是,Java,python,go都有,他們的文件操作方法是不一樣的?如何處理這種現象呢? 有沒有一種統(tǒng)一的視角,看待所有的語言文件從操作呢?
3.操作文件的時候,第一件事情,就是打開文件,打開文件時做什么呢?如何理解呢?
4.文件 = 內容 + 屬性 -> 針對文件的操作,對內容的操作,對屬性的操作
5.當文件沒有被操作的時候,文件一般會在什么位置? 磁盤!
6.當我們對文件進行操作的時候,文件需要在哪里? 內存,為什么呢? 因為CPU和內存交互
7.當我們對文件進行操作的時候,文件需要提前被load到內存,load是內容還是屬性? 屬性,因為一個文件至少得有屬性
8.當我們對文件進行操作的時候,文件需要提前被load到內存,是不是只有你一個人在load呢?不是,內存中一定存在大量的不同文件的屬性
9.所以綜上,打開文件本質就是將需要的文件屬性加載到內存中,OS內部一定會同時存在大量的被打開的文件,那么操作系統(tǒng)要不要管理這些被打開的文件呢? 要,OS需要先描述,在組織。
先描述,構建在內存中的文件結構體struct file{struct file* next},就可以從磁盤來,被打開的文件
a.每一個被打開的文件,都要在OS內對應文件對象的struct結構體,可以將所有的struct file結構體用某種數據結構鏈接起來--,在OS內部,對被打開的文件進行管理,就被轉換成為了對鏈表的增刪查改。
結論:文件被打開,OS要為被打開的文件,創(chuàng)建對應的內核數據結構
struct file
{
//各種屬性
//各種鏈接關系
}
10.文件其實可以被分開兩大類:磁盤文件,被打開的文件(內存文件)
11.文件被打開,是誰打開呢?OS,但是是誰讓OS打開的呢?用戶(進程為代表的)
12.我們之前的所有的文件操作,都是進程和被打開文件的關系
13.都是進程和被打開文件的關系:struct stak_struct和struct file
復習C文件IO相關操作
下面是用C語言實現對文件log.txt進行操作:
#include <stdio.h>
#define LOG "log.txt"int main()
{// w:默認寫方式打開文件,如果文件不存在,就創(chuàng)建它// 默認如果只是打開,文件內容會自動被清空// 同時,每次進行寫入的時候,都會從最開始進行寫入FILE *fp = fopen(LOG, "w");if (fp == NULL){perror("fopen fail");return 1;}// 正常進行文件操作const char *msg = "hello linux\n";int cnt = 5;while (cnt){fputs(msg, fp);cnt--;}fclose(fp); // 關閉文件return 0;
}
成功創(chuàng)建了log.txt文件,打開文件
printf相關函數
printf 默認是向顯示器讀取
int main()
{// w:默認寫方式打開文件,如果文件不存在,就創(chuàng)建它// 1. 默認如果只是打開,文件內容會自動被清空// 2. 同時,每次進行寫入的時候,都會從最開始進行寫入FILE *fp = fopen(LOG, "w");if (fp == NULL){perror("fopen fail");return 1;}// 正常進行文件操作const char *msg = "hello linux";int cnt = 5;while (cnt){fprintf(fp, "%s:%d:phw\n", msg, cnt);cnt--;}fclose(fp); // 關閉文件return 0;
}
fprintf
fprintf(stdout, "%s:%d:phw\n", msg, cnt); // Linux一切皆文件,stdout也對應一個文件,顯示器文件
snprintf
寫入到buffer緩沖里
下面測試一下將msg改成phw
這里得出結論, “w"為覆蓋式寫入
追加式寫入"a"選項
讀取文件
系統(tǒng)文件IO操作
open函數
pathname: 要打開或創(chuàng)建的目標文件
flags: 打開文件時,可以傳入多個參數選項,用下面的一個或者多個常量進行“或”運算,構成flags。
參數:
?O_RDONLY: 只讀打開
?O_WRONLY: 只寫打開
?O_RDWR : 讀,寫打開
?這三個常量,必須指定一個且只能指定一個
?O_CREAT : 若文件不存在,則創(chuàng)建它。需要使用mode選項,來指明新文件的訪問權限
?O_APPEND: 追加寫?O_TRUNC:清空文件內容
返回值:
?成功:新打開的文件描述符
?失敗:-1
下面是標志位的舉例程序:
#define ONE 0x1
#define TWO 0x2
#define THREE 0x4
#define FOUR 0X8
#define FIVE 0X10void Print(int flags)
{if (flags & ONE)printf("hello 1\n");if (flags & TWO)printf("hello 2\n");if (flags & THREE)printf("hello 3\n");if (flags & FOUR)printf("hello 4\n");if (flags & FIVE)printf("hello 5\n");
}int main()
{printf("-------------------\n");printf(ONE);printf("-------------------\n");printf(TWO);printf("-------------------\n");printf(FOUR);printf("-------------------\n");printf(ONE | TWO);printf("-------------------\n");printf(ONE|TWO|THREE);printf("-------------------\n");printf(ONE|TWO|THREE|FOUR|FIVE);printf("-------------------\n");return 0;
}
?
open函數測試:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LOG "log2/txt"// 系統(tǒng)方案
int main()
{int fd = open(LOG, O_WRONLY);printf("fd:%d\n", fd);return 0;
}
文件不存在
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#define LOG "log2/txt"// 系統(tǒng)方案
int main()
{int fd = open(LOG, O_WRONLY |O_CREAT);if (fd == -1){printf("fd:%d,errno:%d,errstring:%s\n", fd, errno, strerror(errno));}else{printf("fd:%d,errno:%d,errstring:%s\n", fd, errno, strerror(errno));}close(fd);return 0;
}
我們在使用open函數的時候不僅要O_WRONLY (寫)還要創(chuàng)建O_CREAT
但是這種方式創(chuàng)建的文件,是沒有權限的。
其中參數mode就是權限
因為umask默認權限的原因
umask()函數
umask() 函數的參數為一個八進制數,它的每一位分別表示對應的文件權限是否會被屏蔽掉,例如,umask(022) 表示屏蔽掉寫入權限和執(zhí)行權限。
umask(0)這意味著沒有任何權限被屏蔽掉。
?將mask初始化為0
?
?成功將文件的權限設置成自己想要的
wirte()函數
?
?這里的strlen不需要+1,\0是C語言的規(guī)定,不是文件的規(guī)定,\0會被解釋成亂碼
O_WRONLY | O_CREAT?默認不會對原始文件內容做清空,需要加上O_TRUNC
?O_APPEND | O_CREAT 不會追加寫,需要加上O_WRONLY
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define LOG "log.txt"// 系統(tǒng)方案
int main()
{umask(0);int fd = open(LOG, O_RDONLY, 0666);if (fd == -1){printf("fd:%d,errno:%d,errstring:%s\n", fd, errno, strerror(errno));}else{printf("fd:%d,errno:%d,errstring:%s\n", fd, errno, strerror(errno));}char buffer[1024];// 這里無法做到按行讀取,我們是整體讀取的ssize_t n = read(fd, buffer, sizeof(buffer) - 1); //使用系統(tǒng)接口來進行IO的時候,一定要注意\0的問題if (n > 0){buffer[n] = '\0';printf("%s\n", buffer);}close(fd);return 0;
}
?
open函數返回值
在認識返回值之前,先來認識一下兩個概念: 系統(tǒng)調用和庫函數
上面的 fopen fclose fread fwrite 都是C標準庫當中的函數,我們稱之為庫函數(libc)。
而, open close read write lseek 都屬于系統(tǒng)提供的接口,稱之為系統(tǒng)調用接口
回憶一下我們講操作系統(tǒng)概念時,畫的一張圖??
?系統(tǒng)調用接口和庫函數的關系,一目了然。 所以,可以認為,f系列的函數,都是對系統(tǒng)調用的封裝,方便二次開發(fā)。