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