Opening Files
The Open() System Call
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (const char *name, int flags);
int open (const char *name, int flags, mode_t mode);
Flags for open()
- O_RDONLY
- O_WRONLY
- O_RDWR
- O_APPEND
- O_ASYNC(當(dāng)指定的文件變?yōu)榭勺x或可寫(xiě)時(shí)珊膜,將生成信號(hào)(默認(rèn)情況下為SIGIO)诗茎。此標(biāo)志僅適用于FIFO、管道穿扳、套接字和終端蹈丸,而不適用于常規(guī)文件壁涎。)
- O_CLOEXEC(在打開(kāi)的文件上設(shè)置關(guān)閉的EXEC標(biāo)志坏瘩。執(zhí)行新進(jìn)程后,文件將自動(dòng)關(guān)閉。這樣就無(wú)需調(diào)用fcntl()來(lái)設(shè)置fand柬脸,從而消除了爭(zhēng)用條件他去。此標(biāo)志僅在Linux內(nèi)核2.6及更高版本中可用。)
- O_CREAT(如果以名稱(chēng)表示的文件不存在倒堕,內(nèi)核將創(chuàng)建它灾测。如果文件已經(jīng)存在,則除非給出O_EXCL涩馆,否則此標(biāo)志無(wú)效行施。)
- O_DIRECT(該文件將被打開(kāi)用于Direct I/O)
- O_DIRECTORY(如果name不是目錄允坚,則對(duì)open()的調(diào)用將失敗魂那。opendir()庫(kù)調(diào)用在內(nèi)部使用此標(biāo)志。)
- O_EXCL(當(dāng)使用O_CREAT時(shí)稠项,如果名稱(chēng)給定的文件已經(jīng)存在涯雅,則此標(biāo)志將導(dǎo)致對(duì)open()的調(diào)用失敗。這用于防止在創(chuàng)建文件時(shí)出現(xiàn)爭(zhēng)用條件展运。如果O_CREAT沒(méi)有提供活逆, 這這個(gè)標(biāo)志位沒(méi)有任何意義。)
- O_LARGEFILE(給定的文件將使用64位偏移打開(kāi)拗胜,允許對(duì)大于2G的文件進(jìn)行操作蔗候。這是隱含在64位架構(gòu)上的。)
- O_NOATIME+ (文件不會(huì)因?yàn)樽x而更新access time埂软,防止一些重要的寫(xiě)行為被讀而覆蓋)
- O_NOCTTY(如果給定的名稱(chēng)引用終端設(shè)備(例如锈遥,/dev/TTY),它將不會(huì)成為進(jìn)程的控制終端勘畔,即使該進(jìn)程目前沒(méi)有控制終端所灸。這個(gè)標(biāo)志位不常使用。)
- O_NOFOLLOW(如果文件名字是一個(gè)symbolic link, 那么調(diào)用open()會(huì)失敗炫七。通常爬立,鏈接被解析,目標(biāo)文件被打開(kāi)万哪。如果給定路徑中的其他組件是鏈接侠驯,則調(diào)用仍將成功。例如奕巍,如果名稱(chēng)為/etc/ship/plank.txt陵霉,如果plank.txt是一個(gè)symbolic link,則失敗伍绳。然而踊挠,如果etc或ship是symbolic links,只要plank.txt不是,它就會(huì)成功效床。)
- O_NONBLOCK(如果可能睹酌,文件將以非阻塞模式打開(kāi)。OPEN()調(diào)用和任何其他操作都不會(huì)導(dǎo)致進(jìn)程阻塞I/O上的(睡眠)剩檀。這種行為只能為FIFO定義憋沿。)
- O_SYNC(該文件將為同步I/O打開(kāi),在數(shù)據(jù)被物理寫(xiě)入磁盤(pán)之前不會(huì)完成寫(xiě)入操作沪猴;正常的讀取操作已經(jīng)是同步的辐啄,因此標(biāo)對(duì)對(duì)讀沒(méi)有影響。)
- O_TRUNC(如果文件存在运嗜,它是一個(gè)常規(guī)文件壶辜,并且給定的標(biāo)志允許寫(xiě)入,該文件將被截?cái)酁榱汩L(zhǎng)度担租。在FIFO或終端設(shè)備上使用O_TRUNC是被忽略的砸民。用于其他文件類(lèi)型是未定義的。使用O_RDONLY指定O_TRUNC也是未定義的奋救,因?yàn)槟枰獙?duì)文件進(jìn)行寫(xiě)訪問(wèn)才能截?cái)嗨?
int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY);
if(fd == -1){
perror("open");
return -1;
}
close(fd);
return 0;
}
沒(méi)有O_TRUNC
int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY | O_TRUNC);
if(fd == -1){
perror("open");
return -1;
}
close(fd);
return 0;
}
有O_TRUNC
很明顯岭参,帶有O_TRUNC寫(xiě)文件時(shí)的效果就是先把文件先清空,再寫(xiě)入
驗(yàn)證如下
int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY | O_TRUNC);
if(fd == -1){
perror("open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}
先寫(xiě)一個(gè)
int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY | O_TRUNC);
if(fd == -1){
perror("open");
return -1;
}
char buf[5] = "bbbb";
write(fd, buf, 5);
close(fd);
return 0;
}
再寫(xiě)一個(gè)
通過(guò)如上的實(shí)驗(yàn)尝艘,結(jié)論得以驗(yàn)證
新文件的所有者
文件所有者的uid是創(chuàng)建文件的進(jìn)程的uid
默認(rèn)行為是將文件的gid設(shè)置為創(chuàng)建文件的進(jìn)程的gid演侯。
新文件的權(quán)限
之前給的兩個(gè)關(guān)于open函數(shù)的調(diào)用形式都是有效的。參數(shù)mode可以被忽略除非文件是被創(chuàng)建的背亥,也是就說(shuō)要給出O_CREAT秒际。當(dāng)你使用O_CREAT時(shí)但忘記提供mode參數(shù)的時(shí)候,那么結(jié)果是不明確的隘梨,而且非常丑陋──所以不要忘記程癌!
- S_IRWXU 所有者具有讀取、寫(xiě)入和執(zhí)行權(quán)限轴猎。
- S_IRUSR 所有這具有讀取的權(quán)限
- S_IWUSR 所有者具有寫(xiě)入的權(quán)限
- S_IXUSR 所有者具有執(zhí)行的權(quán)限
- S_IRWXG 組具有讀取嵌莉、寫(xiě)入和執(zhí)行權(quán)限
- S_IRGRP 組具有讀取的權(quán)限
- S_IWGRP 組具有寫(xiě)入的權(quán)限
- S_IXGRP 組具有執(zhí)行的權(quán)限
- S_IRWXO 每個(gè)人都可以寫(xiě)入、讀取和執(zhí)行
- S_IROTH 每個(gè)人都可以讀取
- S_IWOTH 每個(gè)人都可以寫(xiě)入
- S_IXOTH 每個(gè)人都可以執(zhí)行
例如捻脖,下面的代碼打開(kāi)文件提供的用于寫(xiě)入锐峭。如果文件不存在,使用權(quán)限0644創(chuàng)建該文件可婶。如果確實(shí)存在沿癞,則將其截?cái)酁榱汩L(zhǎng)度:
int testMode()
{
int fd = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
// int fd = open("test1.txt", O_CREAT | O_EXCL,
// S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
if(fd == -1){
perror("testMode - open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}
如果此時(shí)再用以下代碼,則會(huì)發(fā)現(xiàn)報(bào)以下錯(cuò)誤:
int testMode()
{
// int fd = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC,
// S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
int fd = open("test1.txt", O_CREAT | O_EXCL,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
if(fd == -1){
perror("testMode - open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}
創(chuàng)建文件但文件已存在
如果此時(shí)把文件刪除矛渴,再次調(diào)用以上代碼椎扬,則會(huì)發(fā)現(xiàn):
試驗(yàn)1
也就是說(shuō)明惫搏,在文件創(chuàng)建時(shí)沒(méi)有提供寫(xiě)的權(quán)限,文件可以創(chuàng)建蚕涤,但是不會(huì)被寫(xiě)入筐赔,并且可以看到權(quán)限的設(shè)置是按照預(yù)期的。
最后讓我們先刪除文件揖铜,再加入寫(xiě)的權(quán)限并創(chuàng)建文件看一下:
int testMode()
{
// int fd = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC,
// S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
int fd = open("test1.txt", O_CREAT | O_EXCL | O_WRONLY,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
if(fd == -1){
perror("testMode - open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}
試驗(yàn)2
我們發(fā)現(xiàn)文件按照預(yù)期權(quán)限創(chuàng)建茴丰,并且因?yàn)槲覀冊(cè)趧?chuàng)建文件時(shí)加入了寫(xiě)的權(quán)限,因此成功寫(xiě)入了想要的內(nèi)容天吓。