[TOC] 1. 文件類型 Linux下一切皆文件,但文件也分為7種類型,文件類型信息包含在struct stat結構的st_mode成員中,可以用下表中的巨集來檢測文件類型,這些巨集的參數都是stat.st_mode。 | 文件類型 | 說 明 | 檢測文件類型的巨集 | | | | | 普通文件 | ...
目錄
1. 文件類型
Linux下一切皆文件,但文件也分為7種類型,文件類型信息包含在struct stat結構的st_mode成員中,可以用下表中的巨集來檢測文件類型,這些巨集的參數都是stat.st_mode。
文件類型 | 說 明 |
---|---|
普通文件 | 最常用的文件類型,包含某種類型的數據,Linux不關心這些數據是文本還是二進位 |
目錄文件 | 包含目錄中其他文件的名字,以及與這些文件相關信息的指針 |
塊特殊文件 | 提供對設備帶緩衝的訪問,每次訪問長度固定 |
字元特殊文件 | 提供對設備不帶緩衝的訪問,每次訪問長度可變 |
FIFO | 有名單向半雙工管道,用於進程間通信 |
套接字 | socket,用於進程間網路通信 |
符號鏈接 | 文件本身只是個鏈接,指向另一個文件 |
struct stat是記錄文件信息的結構體,結構體定義如下所示,可以調用stat、fstat、lstat函數來獲取文件信息,其中ls -l命令就是基於stat實現的。
struct stat
{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* file type & protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
//成功返回0,失敗返回-1
int stat(const char *path, struct stat *buf); //通過路徑名pathname獲取
int fstat(int fd, struct stat *buf); //通過文件描述符fd獲取
int lstat(const char *path, struct stat *buf); //和stat唯一區別在於返回符號鏈接文件自身信息,而不是指向文件的信息
2. 文件訪問許可權
stat.st_mode也包含了對文件的訪問許可權位,每個文件有9個訪問許可權位,可將它們分成3類,如下表所示,其中前3行中,術語用戶指的是文件所有者(owner)。
st_mode mask | 含 義 |
---|---|
S_IRUSR S_IWUSR S_IXUSR |
user-read user-write user-execute |
S_IRGRP S_IWGRP S_IXGRP |
group-read group-write group-execute |
S_IROTH S_IWOTH S_IXOTH |
other-read other-write other-execute |
access函數
access函數可以測試對某個文件的訪問許可權。
#include <unistd.h>
//成功返回0,失敗返回-1
int access(const char *pathname, int mode);
- 如果測試文件是否存在,mode就為F_OK,否則mode是由R_OK、W_OK、X_OK三個常值按位或組成的
- R_OK、W_OK、X_OK分別測試對目標文件的讀、寫、可執行許可權
umask函數
umask函數為進程設置文件模式創建屏蔽字,並返回之前的值,該函數沒有出錯返回值。
#include <sys/types.h>
#include <sys/stat.h>
//返回之前的文件模式創建屏蔽字
mode_t umask(mode_t mask);
- mask是由上面表格列出的9個st_mode mask常值按位或組成的
- 設置完成後,由當前進程創建的新文件將關閉由mask指定的訪問許可權
- umask函數只會影響當前進程
chmod函數
chmod函數可以改變已有文件的訪問許可權。
#include <sys/stat.h>
//參數mode即為新訪問許可權;成功返回0,失敗返回-1
int chmod(const char *path, mode_t mode);
3. 符號鏈接
符號鏈接是對一個文件的間接指針,也被稱為軟鏈接,它與硬鏈接有所不同,硬鏈接直接指向文件的i節點,引入符號鏈接的原因是為了避開硬鏈接的一些限制。
- 硬鏈接通常要求鏈接和文件位於同一文件系統中,而符號鏈接無此限制
- 只有root用戶才能創建指向目錄的硬鏈接,而符號鏈接任何用戶都可以創建
符號鏈接一般用於將一個文件或整個目錄結構移到系統中另一個位置。
4. 文件與目錄操作
刪除文件
創建文件可以調用open函數,刪除文件則需要調用unlink函數。
#include <unistd.h>
//成功返回0,失敗返回-1
int unlink(const char *pathname);
該函數將pathname引用文件的鏈接計數減1,若鏈接計數達到0,則刪除該文件。
創建目錄
mkdir函數用於創建一個新的空目錄,並自動創建.和..目錄項。
#include <sys/stat.h>
#include <sys/types.h>
//成功返回0,失敗返回-1
int mkdir(const char *pathname, mode_t mode);
mode指定目錄訪問許可權,通常至少需要設置一個執行許可權位,以允許訪問該目錄中的文件名。
刪除目錄
rmdir函數用於刪除一個空目錄,空目錄是只包含.和..的目錄。
#include <unistd.h>
//成功返回0,失敗返回-1
int rmdir(const char *pathname);
讀目錄
只要具有訪問許可權,任何用戶都可以讀目錄,但是只有內核才能寫目錄,寫許可權位和可執行許可權位只決定能否在該目錄中創建和刪除文件,並不代表能否寫目錄本身。
和讀文件一樣,讀目錄也包括三個函數:opendir、readdir、closedir。
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); //成功返回指針,失敗返回NULL
struct dirent *readdir(DIR *dirp); //成功返回指針,失敗返回NULL
int closedir(DIR *dirp); //成功返回0,失敗返回-1
/* On Linux, the dirent structure is defined as follows: */
struct dirent
{
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported by all file system types */
char d_name[256]; /* filename */
};
/* d_type value is defined as follows */
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a Unix domain socket.
DT_UNKNOWN The file type is unknown.
目錄操作示例代碼:遞歸遍歷目錄,列印所有文件路徑
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
void display_dir(char *dir_path)
{
DIR *dir_ptr;
int dir_len;
struct dirent *file_info;
char sub_dir[256];
if (dir_path == NULL)
{
return;
}
dir_ptr = opendir(dir_path);
dir_len = strlen(dir_path);
if (dir_path[dir_len - 1] == '/')
{
dir_path[dir_len - 1] = '\0'; //統一輸出方式,避免出現dir//file.txt的現象
}
while (file_info = readdir(dir_ptr))
{
if (strcmp(file_info->d_name, ".") == 0 || strcmp(file_info->d_name, "..") == 0)
continue;
switch (file_info->d_type)
{
case DT_DIR:
sprintf(sub_dir, "%s/%s", dir_path, file_info->d_name);
display_dir(sub_dir);
break;
case DT_REG:
case DT_BLK:
case DT_CHR:
case DT_FIFO:
case DT_LNK:
printf("%s/%s\n", dir_path, file_info->d_name);
break;
default:
break;
}
}
closedir(dir_ptr);
}
int main(int argc, char *argv[])
{
display_dir(argv[1]);
return 0;
}