O_RDONLY:只讀方式打開
O_WRONLY:只寫方式打開
O_RDWR:可讀寫方式打開
O_CREAT:若路徑中文件不存在則創(chuàng)建,使用 Open 函數(shù)時需同時指定文件權限
O_EXCL:若與 O_CREAT 連用,檢查文件是否已經(jīng)存在,若不存在則建立文件存在則返回錯誤,這使創(chuàng)建和測試成為一個原子操作
O_APPEND:讀寫文件從文件尾部開始移動,所有寫入數(shù)據(jù)都加入文件尾部
O_TRUNC:若文件存在并且可以寫入,此標識會將源文件內容清空
O_NONBLOCK:如果打開或創(chuàng)建文件是管道文件,或一個塊特殊文件,一個字符特殊文件,該表示代表后續(xù)操作非阻塞
S_IRUSR:用戶讀權限
S_IWUSR:用戶寫權限
S_IXUSR:用戶執(zhí)行權限
S_IRWX:用戶讀寫執(zhí)行權限
S_IRGRP:用戶組讀權限
S_IWGRP:用戶組寫權限
S_IXGRP:用戶組執(zhí)行權限
S_IRWXG:用戶組讀寫執(zhí)行權限
S_IROTH:其他用戶讀權限
S_IWOTH:其他用戶寫權限
S_IXOTH:其他用戶執(zhí)行權限
S_IRWXO:其他用戶讀寫執(zhí)行權限
S_ISUID:SUID 權限
S_ISGID:SGID 權限
O_SYNC:每次 write 都等到物理 I/O 完成才返回,包括文件屬性更新 I/O 操作完成
O_DSYNC: 每次 write 都等到物理 I/O 完成才返回,不包括文件屬性更新 I/O 操作完成
O_RSYNC:使每一個以文件描述符作為參數(shù)的 read 的參數(shù)等待,直到任何對文件同一部分進行的寫操作都完成
open
用于打開或創(chuàng)建文件
Int open(文件路徑,標識,權限標識)
文件路徑:絕對路徑與相對路徑均可
標識:文件標識與操作副標識以及文件同步標識的結合結合
權限標識:是使用權限標識,也可用數(shù)字法標識
返回值:成功返回文件標識符.出錯返回-1
creat
用于創(chuàng)建文件
int creat(文件路徑, 權限標識)
返回值:成功返回文件標識符.出錯返回-1
說明:以只寫方式打開文件
close
用于關閉文件,當一個進程終止時,內核會自動關閉它打開的所有文件
int close(int fd)
返回值:成功返回0.出錯返回-1
sleek
用于設置文件偏移量
off_tsleek(int fd,off_t offset,int whence)
若 whence= SEEK_SET,設置當前偏移量為距離文件開始處 offset 字節(jié)
若 whence= SEEK_CUR,設置當前偏移量為距離文件當前偏移處 offset 字節(jié)(offset 可為正負)
若 whence= SEEK_END,設置當前偏移量為文件長度加 offset(offset 可為正負)
返回值:成功返回新的文件偏移量,失敗返回-1 (對于管道文件不能設置偏移文件,因此返回-1)
dup|dup2
復制一個現(xiàn)存的文件描述符
Int dup(intfd)
Int dup(intfd1,int fd2)
Fd1為復制的文件描述符源
Fd2為復制的文件描述符目的地
如果 fd2文件為關閉應先關閉
返回值:成功返回新的文件描述符,失敗返回-1
舉例:
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
int main() {
int f = open("output", O_CREAT | O_TRUNC | O_RDWR, 0644);
if (f == -1) {
perror("文件創(chuàng)建失??!");
return 0;
}
int newf = dup(f);
write(f, "往文件里寫輸入!\n", 25);
write(newf, "使用新的文件描述符!\n", 31);
int oldInput = dup(STDOUT_FILENO);
puts("使用標準輸出到控制臺");
dup2(f, STDOUT_FILENO);
puts("使用標準輸出到文件");
dup2(oldInput, STDOUT_FILENO);
puts("還原標準輸出到控制臺");
return 0;
}
控制臺輸出:
使用標準輸出到控制臺
還原標準輸出到控制臺
output 文件內容:
往文件里寫輸入!
使用新的文件描述符!
使用標準輸出到文件
fcnt1
改變已打開文件的文件性質
int fcntl (int fd, int cmd, ...);
主要功能:
1: 復制一個現(xiàn)有描述符:Cmd=F_DUPFD
2:獲取/設置文件描述符標注 cmd= F_GETFD 或 F_SETFD
3:獲取/設置文件狀態(tài)標注 cmd=F_GETFL 或 F_SETFL
4:獲取/設置異步 I/O 所有權 cmd= F_GETOWN 或 F_SETOWN
5:獲取/設置記錄鎖 cmd= F_GETLK 或 F_SETLK
Fcntl 的文件狀態(tài)標識
O_RDONLY
O_WRONLY
O_RDWR
O_APPENT
O_NONBLOCK
O_SYNC
O_DSYNC
O_FSYNC
說明:
1:由于 O_RDONLY,O_WRONLY,O_RDWR 只能同時存在一個,因此需要用 O_ACCMODE 取得訪問屏蔽位
2:F_SETFL 只能設置 O_APPENT,O_NONBLOCK,O_SYNC,O_DSYNC,O_FSYNC
舉例:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd = open("fcnt", O_RDWR | O_APPEND|O_SYNC );
printf("文件描述符=%d\n", fd);
int flag = fcntl(fd, F_GETFL, 0);
switch (flag & O_ACCMODE) {
case O_RDWR:
printf("O_RDWR\n");
break;
case O_RDONLY:
printf("O_RDONLY\n");
break;
case O_WRONLY:
printf("O_WRONLY\n");
break;
default:
printf("default\n");
break;
}
if (flag & O_APPEND) {
printf("O_APPEND\n");
}
#if defined (O_SYNC)
if (flag & O_SYNC) {
printf("O_SYNC\n");
}
#endif
if (flag & O_NONBLOCK) {
printf("O_NONBLOCK\n");
}
close(1);
fcntl(fd,F_DUPFD,1);
puts("通過標準輸出寫到文件\n");
return 0;
}
控制臺輸出
文件描述符=3
O_RDWR
O_APPEND
O_SYNC
sync|fsync|fdatasync
當數(shù)據(jù)寫入文件時,內核通常先將數(shù)據(jù)復制到一個緩沖區(qū)中,如果該緩沖區(qū)尚未寫滿,則不將其排入輸出隊里,直到其寫滿或者內核需要使用這塊緩沖區(qū)做其他使用,這種方式叫做延遲寫
好處是,可以減少 IO 操作,但是帶來的風險就是系統(tǒng)發(fā)生故障時,會造成數(shù)據(jù)的丟失
總結起來,數(shù)據(jù)寫入文件分為以下3步:
1.寫入緩沖區(qū)
2.緩沖區(qū)數(shù)據(jù)排入輸出隊里
3.將緩沖區(qū)數(shù)據(jù)寫入磁盤
void sync (void)
將緩沖區(qū)排入輸出隊里后返回
int fsync (int __fd);
等待數(shù)據(jù)寫入磁盤并且文件屬性更新后返回
int fdatasync (int __fildes);
等待數(shù)據(jù)寫入磁盤返回
access
測試實際用戶是否有相應權限
int access (constchar *name, int mode)
mode:
R_OK:測試讀權限
W_OK:測試寫權限
X_OK:測試執(zhí)行權限
F_OK:測試文件是否存在
文件鏈接分為2種情況
1.硬鏈接:不會產(chǎn)生新的 INODE,IBLOCK,只是在原有數(shù)據(jù)連接數(shù)上+1
不能跨文件系統(tǒng)使用
硬鏈接目錄需要 ROOT 權限
2.軟鏈接:產(chǎn)生的 INODE,IBLOCK,新的 IBLOCK 記錄鏈接的內容
可以跨文件系統(tǒng)使用
對于軟鏈接來說,有些函數(shù)時直接作用鏈接文件本身,有些函數(shù)則跟隨源文件鏈接到源文件
函數(shù) |
不跟隨符號鏈接 |
跟隨符號鏈接 |
access |
√ |
|
chdir |
√ |
|
chmod |
√ |
|
chown |
√ |
√ |
creat |
√ |
|
exec |
√ |
|
lchown |
√ |
|
link |
√ |
|
lstat |
√ |
|
open |
√ |
|
opendir |
√ |
|
pathconf |
√ |
|
readlink |
√ |
|
remove |
√ |
|
rename |
√ |
|
stat |
√ |
|
truncate |
√ |
|
unlink |
√ |
link|unlink
創(chuàng)建文件的硬鏈接
int link (constchar __from, constchar __to)
刪除一個文件
int unlink (constchar *__name)
說明:對于硬鏈接來說 unlink 只是刪除文件鏈接符,文件實際數(shù)據(jù)的連接數(shù)-1,如果為文件實際數(shù)據(jù)0則在所有進程關閉對此文件連接時刪除
舉例
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#define BUFFER_SIZE 409600
int printfilestat(int fd, struct stat *buf) {
int results = fstat(fd, buf);
if (results == -1) {
perror("文件屬性獲取失敗");
return -1;
}
printf("文件連接數(shù)是=%d\n", buf->st_nlink);
return 0;
}
int main() {
int fd = open("linkfile", O_RDWR, 0777);
if (fd == -1) {
perror("文件打開失敗");
return -1;
}
struct stat buf;
printfilestat(fd, &buf);
if (link("linkfile", "newlinkfile") == 0) {
puts("鏈接文件創(chuàng)建成功");
}
printfilestat(fd, &buf);
if (unlink("newlinkfile") == 0) {
puts("newlinkfile文件刪除成功");
}
printfilestat(fd, &buf);
if (unlink("linkfile") == 0) {
puts("linkfile文件刪除成功");
}
printfilestat(fd, &buf);
sleep(30);
close(fd);
puts("關閉文件!");
sleep(-1);
return 0;
}
控制臺輸出
文件連接數(shù)是=1
鏈接文件創(chuàng)建成功
文件連接數(shù)是=2
newlinkfile 文件刪除成功
文件連接數(shù)是=1
linkfile 文件刪除成功
文件連接數(shù)是=0
雖然文件連接數(shù)為0 但是文件數(shù)據(jù)沒有被刪除,需要等待所有進程都 close 該文件才會被從磁盤刪除
tkf@tkf:~/workspace/FileOperator$ ll linkfile ;df ./
-rwxrwxr-x 1 tkf tkf 4096005月9 16:34linkfile*
文件系統(tǒng)1K-blocks已用可用已用% 掛載點
/dev/sda128768380 17972780931121266% /
執(zhí)行程序
tkf@tkf:~/workspace/FileOperator$ df ./
文件系統(tǒng)1 K-blocks 已用可用已用% 掛載點
/dev/sda128768380 17972784931120866% /
linkfile, newlinkfile 文件符號連接刪除,因此可用資源變多了
sleep(30)
tkf@tkf:~/workspace/FileOperator$df ./
文件系統(tǒng)1 K-blocks 已用可用已用% 掛載點
/dev/sda128768380 17972344931164866% /
執(zhí)行了 close,因此在無進程來接到數(shù)據(jù),所以文件數(shù)據(jù)被釋放,可用資源再一次變多了
symlink|readlink
創(chuàng)建一個軟鏈接
int symlink (constchar __from, constchar __to)
返回值:成功返回0,失敗返回-1
打開軟鏈接文件
ssize_t readlink (constchar restrict path,
char restrict buf, size_t __len)
返回值:成功返回0,失敗返回-1
獲取文件狀態(tài)
Int fstat(文件標識符,struct stat buf)
Int lstat(文件路徑,struct stat buf)
*Int stat(文件路徑,struct stat buf)**
文件路徑:絕對路徑與相對路徑均可
文件標識符:文件創(chuàng)建或打開時返回的文件標示符
*struct stat buf:**文件屬性結構體
返回值:成功返回0,失敗返回-1
說明:stat 和 lstat 的區(qū)別:當文件是一個符號鏈接時,lstat 返回的是該符號鏈接本身的信息;而 stat 返回的是該鏈接指向的文件的信息
struct stat {
dev_t st_dev; 文件所在設備的 ID
ino_t st_ino; 與該文件關聯(lián)的 inode
mode_t st_mode;
nlink_t st_nlink; / 鏈向此文件的連接數(shù)(硬連接)/
uid_t st_uid; 文件屬主的 UID 號
gid_t st_gid; 文件屬主的 GID 號
dev_t st_rdev; 設備號,針對設備文件
off_t st_size; 文件大小
blksize_t st_blksize; 系統(tǒng)塊的大小(IO 緩沖區(qū)適合大小)
blkcnt_t st_blocks; 文件所占塊數(shù)
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
}
文件類型標志:
S_IFBLK:文件是一個特殊的塊設備
S_IFDIR:文件是一個目錄
S_IFCHR:文件是一個特殊的字符設備
S_IFIFO:文件是一個 FIFO 設備
S_IFREG:文件是一個普通文件(REG 即使 regular 啦)
S_IFLNK:文件是一個符號鏈接
其他模式標志:
S_ISUID: 文件設置了 SUID 位
S_ISGID:文件設置了 SGID 位
S_ISVTX:文件設置了 SBIT 位
用于解釋 st_mode 標志的掩碼:
S_IFMT:文件類型
S_IRWXU:屬主的讀/寫/執(zhí)行權限,可以分成 S_IXUSR,S_IRUSR, S_IWUSR
S_IRWXG:屬組的讀/寫/執(zhí)行權限,可以分成 S_IXGRP,S_IRGRP, S_IWGRP
S_IRWXO:其他用戶的讀/寫/執(zhí)行權限,可以分為 S_IXOTH,S_IROTH, S_IWOTH
確定文件類型
S_ISBLK:測試是否是特殊的塊設備文件
S_ISCHR:測試是否是特殊的字符設備文件
S_ISDIR:測試是否是目錄(我估計 find .-type d 的源代碼實現(xiàn)中就用到了這個宏)
S_ISFIFO:測試是否是 FIFO 設備
S_ISREG:測試是否是普通文件
S_ISLNK:測試是否是符號鏈接
S_ISSOCK:測試是否是 socket
umask
設置文件權限屏蔽字
mode_t umask (mode_t __mask)
chmod|lchmod|fchmod
設置文件權限
int chmod (constchar file, __mode_tmode)
int lchmod (constchar file, __mode_tmode)
int fchmod (int fd, mode_tmode)
chown|fchown|lchown
設置文件所屬用戶及用戶組
int chown (constchar file, uid_t owner, gid_tgroup)
int fchown (int fd, uid_t owner, gid_t group) _
int lchown (constchar file, uid_t owner, gid_t __group)
Int mkdir(路徑,權限)
路徑:絕對路徑相對路徑均可
權限:以數(shù)字形式表示的權限
返回值:成功返回0,失敗返回-1
進入工作目錄
Int chdir(路徑)
路徑:絕對路徑相對路徑均可
返回值:成功返回0,失敗返回-1
Int fchdir(intfiledes)
返回值:成功返回0,失敗返回-1
獲取工作目錄
char getcwd (char __buf, size_t __size)
返回值:當前工作目錄
子目錄流操作
打開目錄,獲得子目錄流指針
DIRopendir(char name)
讀取子目錄
structdirent readdir((DIR dirp)
返回子目錄流里的當前位置
*longint telldir(DIR drip)**
設置子目錄流的當前數(shù)據(jù)項指針
*voidseekdir(DIR drip,long int loc)**
關閉子目錄流
DIRopendir(DIR drip)
刪除目錄或文件
刪除目錄:int rmdir(路徑)
刪除文件:int unlink(路徑)
返回值:成功返回1,失敗返回-1
#include<fcntl.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<dirent.h>
#include<stdlib.h>
typedefenum {
false = 0, true = 1
} bool;
voidprintFileInfo(struct stat* buf) {
bool userall = false;
printf("文件權限是:%o. 詳細信息如下:\n", (buf->st_mode& 0x0fff));
if (buf->st_mode& S_IRWXU) {
userall = true;
printf("所有者擁有讀寫執(zhí)行權限\n");
}
if (buf->st_mode& S_IRWXG) {
printf("用戶組擁有讀寫執(zhí)行權限\n");
}
if (buf->st_mode& S_IRWXO) {
printf("其他人擁有讀寫執(zhí)行權限\n");
}
if (userall) {
if (buf->st_mode& S_IRUSR) {
printf("所有者擁有讀權限\n");
}
if (buf->st_mode& S_IWUSR) {
printf("所有者擁有寫權限\n");
}
}
if (buf->st_mode& S_IFREG) {
printf("文件是一個普通文件\n");
}
if (buf->st_mode& S_ISUID) {
printf("文件設置了 SUID 權限\n");
}
if (buf->st_mode& S_ISGID) {
printf("文件設置了 GUID 權限\n");
}
printf("UID=%d\n", buf->st_uid);
printf("GID=%d\n", buf->st_gid);
printf("占用block=%ld\n", buf->st_blocks);
printf("block大小=%ld\n", buf->st_blksize);
printf("最后訪問時間=%ld\n", buf->st_atim.tv_sec);
printf("最后狀態(tài)更新時間=%ld\n", buf->st_ctim.tv_sec);
printf("最后修改時間=%ld\n", buf->st_mtim.tv_sec);
}
intOpenFile(constchar *fpath) {
unlink(fpath);
int f = open(fpath, O_RDWR);
if (f == -1) {
f = creat(fpath, S_IWUSR | S_IRUSR);
if (f != -1) {
printf("創(chuàng)建一個文件\n");
} else {
printf("無法創(chuàng)建文件\n");
return -1;
}
} else {
printf("文件打開成功\n");
}
return f;
}
voidscan_dir(constchar* dir, int depth) {
DIR *dp;
struct dirent* entry;
if ((dp = opendir(dir)) == NULL) {
printf("無法打開目錄:%s\n", dir);
return;
}
struct stat statbuf;
chdir(dir);
while ((entry = readdir(dp)) != NULL) {
constchar* name = entry->d_name;
lstat(name, &statbuf);
if (S_IFDIR & statbuf.st_mode) {
if (strcmp(".", entry->d_name) == 0
|| strcmp("..", entry->d_name) == 0) {
continue;
}
printf("%*s%s:%o\n", depth, "", entry->d_name,
(statbuf.st_mode& 0x0fff));
scan_dir(entry->d_name, depth + 4);
} else {
printf("%*s%s:%o\n", depth, "", entry->d_name,
(statbuf.st_mode& 0x0fff));
}
}
chdir("..");
closedir(dp);
}
intmain() {
constchar *fpath = "test";
int f = OpenFile(fpath);
struct stat *buf = malloc(sizeof(struct stat));
fstat(f, buf);
printf("===================================================\n");
printFileInfo(buf);
printf("===================================================\n");
close(f);
sleep(1);
chmod("test", 7777);
printf("更改文件權限為7777\n");
stat("test", buf);
printf("===================================================\n");
printFileInfo(buf);
printf("===================================================\n");
free(buf);
printf("==================掃描文件夾============================\n");
scan_dir("/home", 0);
umask(0011);
mkdir("/tmp/mydir", 0777);
creat("/tmp/mydir/myfile", 0777);
printf("==================掃描文件夾==========================\n");
scan_dir("/tmp/mydir", 0);
chdir("/tmp");
unlink("mydir/myfile");
rmdir("mydir");
return 0;
}
執(zhí)行結果
創(chuàng)建一個文件
文件權限是:600. 詳細信息如下:
所有者擁有讀寫執(zhí)行權限
所有者擁有讀權限
所有者擁有寫權限
文件是一個普通文件
UID=0
GID=0
占用 block=8
block 大小=4096
最后訪問時間=1397539372
最后狀態(tài)更新時間=1397539372
最后修改時間=1397539372
更改文件權限為7777
文件權限是:7141. 詳細信息如下:
所有者擁有讀寫執(zhí)行權限
用戶組擁有讀寫執(zhí)行權限
其他人擁有讀寫執(zhí)行權限
文件是一個普通文件
文件設置了 SUID 權限
文件設置了 GUID 權限
UID=0
GID=0
占用 block=8
block 大小=4096
最后訪問時間=1397539372
最后狀態(tài)更新時間=1397539373
最后修改時間=1397539372
掃描文件夾
.bashrc:644
.bash_logout:644
.mozilla:755
extensions:755
plugins:755
.nautilus:755
metafiles:700
目錄創(chuàng)建成功
文件創(chuàng)建成功
掃描文件夾
myfile:766
文件刪除成功
目錄刪除成功