Linux學習記錄--文件管理相關係統編程

文件管理相關係統編程


重要文件標識


打開文件標識

O_RDONLY:只讀方式打開

O_WRONLY:只寫方式打開

O_RDWR:可讀寫方式打開


打開文件操作副標識

O_CREAT:若路徑中文件不存在則創建,使用Open函數時需同時指定文件權限

O_EXCL:若與O_CREAT連用,檢查文件是否已經存在,若不存在則建立文件存在則返回錯誤,這使創建和測試成爲一個原子操作

O_APPEND:讀寫文件從文件尾部開始移動,所有寫入數據都加入文件尾部

O_TRUNC:若文件存在並且可以寫入,此標識會將源文件內容清空

O_NONBLOCK:如果打開或創建文件是管道文件,或一個塊特殊文件,一個字符特殊文件,該表示代表後續操作非阻塞


文件權限標誌

S_IRUSR:用戶讀權限

S_IWUSR:用戶寫權限

S_IXUSR:用戶執行權限

S_IRWX:用戶讀寫執行權限

S_IRGRP:用戶組讀權限

S_IWGRP:用戶組寫權限

S_IXGRP:用戶組執行權限

S_IRWXG:用戶組讀寫執行權限

S_IROTH:其他用戶讀權限

S_IWOTH:其他用戶寫權限

S_IXOTH:其他用戶執行權限

S_IRWXO:其他用戶讀寫執行權限

S_ISUIDSUID權限

S_ISGIDSGID權限


文件同步輸入標識

O_SYNC:每次write都等到物理I/O完成才返回,包括文件屬性更新I/O操作完成

O_DSYNC: 每次write都等到物理I/O完成才返回,不包括文件屬性更新I/O操作完成

O_RSYNC:使每一個以文件描述符作爲參數的read的參數等待,直到任何對文件同一部分進行的寫操作都完成


重要函數


文件操作

open


用於打開或創建文件

Int open(文件路徑,標識,權限標識)

文件路徑:絕對路徑與相對路徑均可

標識:文件標識與操作副標識以及文件同步標識的結合結合

權限標識:是使用權限標識,也可用數字法標識

返回值:成功返回文件標識符.出錯返回-1


creat


用於創建文件

int creat(文件路徑權限標識)

返回值:成功返回文件標識符.出錯返回-1

說明:以只寫方式打開文件


close


用於關閉文件,當一個進程終止時,內核會自動關閉它打開的所有文件

int close(int fd)

返回值:成功返回0.出錯返回-1


sleek


用於設置文件偏移量

off_tsleek(int fd,off_t offset,int whence)

whence= SEEK_SET,設置當前偏移量爲距離文件開始處offset字節

whence= SEEK_CUR,設置當前偏移量爲距離文件當前偏移處offset字節(offset可爲正負)

whence= SEEK_END,設置當前偏移量爲文件長度加offsetoffset可爲正負)


返回值:成功返回新的文件偏移量,失敗返回-1 (對於管道文件不能設置偏移文件,因此返回-1


dup|dup2


複製一個現存的文件描述符

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("文件創建失敗!");
		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: 複製一個現有描述符:Cmd=F_DUPFD

2:獲取/設置文件描述符標註cmd= F_GETFDF_SETFD

3:獲取/設置文件狀態標註 cmd=F_GETFLF_SETFL

4:獲取/設置異步I/O所有權 cmd= F_GETOWNF_SETOWN

5:獲取/設置記錄鎖 cmd= F_GETLKF_SETLK


Fcntl的文件狀態標識

O_RDONLY

O_WRONLY

O_RDWR

O_APPENT

O_NONBLOCK

O_SYNC

O_DSYNC

O_FSYNC


說明:

1:由於 O_RDONLYO_WRONLYO_RDWR 只能同時存在一個,因此需要用O_ACCMODE取得訪問屏蔽位

2F_SETFL只能設置O_APPENTO_NONBLOCKO_SYNCO_DSYNCO_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


當數據寫入文件時,內核通常先將數據複製到一個緩衝區中,如果該緩衝區尚未寫滿,則不將其排入輸出隊裏,直到其寫滿或者內核需要使用這塊緩衝區做其他使用,這種方式叫做延遲寫

好處是,可以減少IO操作,但是帶來的風險就是系統發生故障時,會造成數據的丟失


總結起來,數據寫入文件分爲以下3步:

1.寫入緩衝區

2.緩衝區數據排入輸出隊裏

3.將緩衝區數據寫入磁盤


void sync (void)

將緩衝區排入輸出隊裏後返回


int fsync (int __fd);

等待數據寫入磁盤並且文件屬性更新後返回


int fdatasync (int __fildes);

等待數據寫入磁盤返回


access

測試實際用戶是否有相應權限

int access (constchar *name, int mode)


mode:

R_OK:測試讀權限

W_OK:測試寫權限

X_OK:測試執行權限

F_OK:測試文件是否存在


文件鏈接


 文件鏈接分爲2種情況

1.硬鏈接:不會產生新的INODE,IBLOCK,只是在原有數據連接數上+1

不能跨文件系統使用

硬鏈接目錄需要ROOT權限


2.軟鏈接:產生的INODE,IBLOCK,新的IBLOCK記錄鏈接的內容

可以跨文件系統使用


對於軟鏈接來說,有些函數時直接作用鏈接文件本身,有些函數則跟隨源文件鏈接到源文件


函數

不跟隨符號鏈接

跟隨符號鏈接

access

 

chdir

 

chmod

 

chown

creat

 

exec

 

lchown

 

link

 

lstat

 

open

 

opendir

 

pathconf

 

readlink

 

remove

 

rename

 

stat

 

truncate

 

unlink

 



link|unlink

創建文件的硬鏈接

int link (constchar *__from, constchar *__to)


刪除一個文件

int unlink (constchar *__name)


說明:對於硬鏈接來說unlink只是刪除文件鏈接符,文件實際數據的連接數-1,如果爲文件實際數據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("文件連接數是=%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("鏈接文件創建成功");
	}
	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;
}


控制檯輸出

文件連接數是=1

鏈接文件創建成功

文件連接數是=2

newlinkfile文件刪除成功

文件連接數是=1

linkfile文件刪除成功

文件連接數是=0


è雖然文件連接數爲但是文件數據沒有被刪除,需要等待所有進程都close該文件纔會被從磁盤刪除



tkf@tkf:~/workspace/FileOperator$ ll linkfile ;df ./

-rwxrwxr-x 1 tkf tkf 40960059 16:34linkfile*

文件系統1K-blocks已用可用已用掛載點

/dev/sda128768380 17972780931121266% /

執行程序


tkf@tkf:~/workspace/FileOperator$ df ./

文件系統1K-blocks已用可用已用掛載點

/dev/sda128768380 17972784931120866% /

linkfile, newlinkfile文件符號連接刪除,因此可用資源變多了


sleep(30)

tkf@tkf:~/workspace/FileOperator$df ./

文件系統1K-blocks已用可用已用掛載點

/dev/sda128768380 17972344931164866% /

執行了close,因此在無進程來接到數據,所以文件數據被釋放,可用資源再一次變多了


symlink|readlink


創建一個軟鏈接

int symlink (constchar *__from, constchar *__to)

返回值:成功返回0,失敗返回-1


打開軟鏈接文件

ssize_t readlink (constchar *__restrict __path,

char *__restrict __buf, size_t __len)

返回值:成功返回0,失敗返回-1


文件狀態和屬性


獲取文件狀態

Int fstat(文件標識符,struct stat *buf)

Int lstat(文件路徑,struct stat *buf)

Int stat(文件路徑,struct stat *buf)


文件路徑:絕對路徑與相對路徑均可

文件標識符:文件創建或打開時返回的文件標示符

struct stat *buf文件屬性結構體


返回值:成功返回0,失敗返回-1


說明:statlstat的區別:當文件是一個符號鏈接時,lstat返回的是該符號鏈接本身的信息;而stat返回的是該鏈接指向的文件的信息


stat 結構體成員意義

struct stat { 

  dev_t       st_dev;  文件所在設備的ID

ino_t       st_ino;   與該文件關聯的inode

mode_t      st_mode;  

  nlink_t     st_nlink;   /* 鏈向此文件的連接數(硬連接)*/ 

uid_t       st_uid;  文件屬主的UID

gid_t       st_gid;    文件屬主的GID

 dev_t       st_rdev;    設備號,針對設備文件

  off_t       st_size;    文件大小

  blksize_t   st_blksize; 系統塊的大小(IO緩衝區適合大小)

  blkcnt_t    st_blocks; 文件所佔塊數

time_t      st_atime; 

 time_t      st_mtime;  

time_t      st_ctime;  

}


st_mode 標誌


文件類型標誌:

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:屬主的讀//執行權限,可以分成S_IXUSR,S_IRUSR, S_IWUSR

S_IRWXG:屬組的讀//執行權限,可以分成S_IXGRP,S_IRGRP, S_IWGRP

S_IRWXO:其他用戶的讀//執行權限,可以分爲S_IXOTH,S_IROTH, S_IWOTH

確定文件類型

S_ISBLK:測試是否是特殊的塊設備文件

S_ISCHR:測試是否是特殊的字符設備文件

S_ISDIR:測試是否是目錄(我估計find .-type d的源代碼實現中就用到了這個宏)

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_t__group)

int fchown (int __fd, __uid_t __owner, __gid_t __group) _

int lchown (constchar *__file, __uid_t __owner, __gid_t __group)


目錄操作


創建目錄

Int mkdir(路徑,權限)

路徑:絕對路徑相對路徑均可

權限:以數字形式表示的權限

返回值:成功返回0,失敗返回-1


進入|獲取工作目錄


進入工作目錄

Int chdir(路徑)

路徑:絕對路徑相對路徑均可

返回值:成功返回0,失敗返回-1


Int fchdir(intfiledes)

返回值:成功返回0,失敗返回-1


獲取工作目錄

char *getcwd (char *__buf, size_t __size)

返回值:當前工作目錄


子目錄流操作


打開目錄,獲得子目錄流指針

DIR*opendir(char *name)


讀取子目錄

structdirent* readdir((DIR *dirp)


返回子目錄流裏的當前位置

longint telldir(DIR* drip)


設置子目錄流的當前數據項指針

voidseekdir(DIR* drip,long int loc)


關閉子目錄流

DIR*opendir(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("所有者擁有讀寫執行權限\n");
	}
	if (buf->st_mode& S_IRWXG) {
		printf("用戶組擁有讀寫執行權限\n");
	}
	if (buf->st_mode& S_IRWXO) {
		printf("其他人擁有讀寫執行權限\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("最後狀態更新時間=%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("創建一個文件\n");
		} else {
			printf("無法創建文件\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;
}


執行結果

創建一個文件

===================================================

文件權限是:600. 詳細信息如下:

所有者擁有讀寫執行權限

所有者擁有讀權限

所有者擁有寫權限

文件是一個普通文件

UID=0

GID=0

佔用block=8

block大小=4096

最後訪問時間=1397539372

最後狀態更新時間=1397539372

最後修改時間=1397539372

===================================================

更改文件權限爲7777

===================================================

文件權限是:7141. 詳細信息如下:

所有者擁有讀寫執行權限

用戶組擁有讀寫執行權限

其他人擁有讀寫執行權限

文件是一個普通文件

文件設置了SUID權限

文件設置了GUID權限

UID=0

GID=0

佔用block=8

block大小=4096

最後訪問時間=1397539372

最後狀態更新時間=1397539373

最後修改時間=1397539372

===================================================

==================掃描文件夾============================

.bashrc:644

.bash_logout:644

.mozilla:755

extensions:755

plugins:755

.nautilus:755

metafiles:700

目錄創建成功

文件創建成功

==================掃描文件夾==========================

myfile:766

文件刪除成功

目錄刪除成功


發佈了107 篇原創文章 · 獲贊 66 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章