linux 文件及目錄操作 chmod,getcwd,chdir,mkdir,rmdir,opendir,readdir,seekdir,telldir、closedir、stat、fstat

改變目錄或文件的訪問權限:

#include <sys/stat.h> 
int chmod(const char* path, mode_t mode);  
//path 參數指定的文件被修改爲具有 mode 參數給出的訪問權限

獲取、改變當前目錄:

#include <unistd.h>   //頭文件 
char *getcwd(char *buf, size_t size);  //獲取當前目錄,相當於 pwd 命令 
int chdir(const char *path);     //修改當前目錄,即切換目錄,相當於 cd 命令

getcwd()函數: 將當前的工作目錄絕對路徑複製到參數 buf 所指的內存空間, 參數 size 爲 buf
的空間大小。倘若參數 buf 爲 NULL,getcwd()會依參數 size 的大小自動配置內存(使用malloc()),如果參數 size 也爲 0,則 getcwd()會 依工作目錄絕對路徑的字符串程度來決定所配置的內存大小,進程可以在使用完此字符串後自動利用 free()來釋放此空間。所以常用的形式:getcwd(NULL, 0)。
chdir()函數:用來將當前的工作目錄改變成以參數 path 所指的目錄。

#include<unistd.h> 
int main() 
{ 
	chdir(/tmp”); 
	printf(“current working directory: %s\n”,getcwd(NULL,0)); 
	return 0;
} 

創建和刪除目錄:

#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
int mkdir(const char *pathname, mode_t mode);  //創建目錄,mode 是目錄權限 
int rmdir(const char *pathname);      //刪除目錄 

獲取目錄信息:

#include <sys/types.h> 
#include <dirent.h> 
DIR *opendir(const char *name);       //打開一個目錄  
struct dirent *readdir(DIR *dir);     //讀取目錄的一項信息,並返回該項信息的結構體指針 
void rewinddir(DIR *dir);             //重新定位到目錄文件的頭部 
void seekdir(DIR *dir,off_t offset);  //用來設置目錄流目前的讀取位置 
off_t telldir(DIR *dir);              //返回目錄流當前的讀取位置 
int closedir(DIR *dir);               //關閉目錄文件

seekdir()用來設置參數dir目錄流讀取位置,在調用readdir()時便從此新位置開始讀取。參數offset 代表距離目錄文件開頭的偏移量。
讀取目錄信息的步驟爲:
1、用 opendir 函數打開目錄;
2、使用 readdir 函數迭代讀取目錄的內容,如果已經讀取到目錄末尾,又想重新開始讀,則可以使用 rewinddir 函數將文件指針重新定位到目錄文件的起始位置;
3、用 closedir 函數關閉目錄
案例:

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    DIR* dir;
    dir = opendir(argv[1]);
    ERROR_CHECK(dir, NULL, "opendir");
    struct dirent *p;
    while(p = readdir(dir))
    {
        printf("Ino = %ld len = %d type = %d filename = %s\n", p->d_ino, p->d_reclen, p->d_type, p->d_name);
    }
    closedir(dir);  
    return 0;
}

案例:

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    DIR* dir;
    dir = opendir(argv[1]);   //打開一個目錄,返回指向該目錄流DIR的指針
    ERROR_CHECK(dir, NULL, "opendir");
    struct dirent *p;
    off_t pos;
    while(p = readdir(dir))   //讀取目錄的一項信息,並返回該項信息的結構體指針 
    {
        printf("Ino = %ld len = %d type = %d filename = %s\n", p->d_ino, p->d_reclen, p->d_type, p->d_name);
        if(!strcmp(p->d_name,"a.out"))
        {
            pos = telldir(dir);  //返回目錄流當前的讀取位置 
        }
    }
    seekdir(dir,pos);   //重新設置目錄流目前的讀取位置
    printf("~~~~~~~~~~~~~~~~~~~~\n");
    p = readdir(dir);
    printf("Ino = %ld len = %d type = %d filename = %s\n", p->d_ino, p->d_reclen, p->d_type, p->d_name);
    closedir(dir);   //關閉目錄文件
    return 0;
}

DIR的結構體定義如下:

struct __dirstream {
    void *__fd; /* `struct hurd_fd' pointer for descriptor.   */
    char *__data;
    int __entry_data;
    char *__ptr;
    int __entry_ptr;
    size_t __allocation;
    size_t __size;
    __libc_lock_define (, __lock)
};
typedef struct __dirstream DIR;      //DIR的定義

DIR爲目錄流,類似於於FILE,這種文件包含了其他文件的名稱和指向其他文件的文件描述符。通過opendir可以打開該目錄流的接口。
opendir()用來打開參數 name 指定的目錄,並返回 DIR*形態的目錄流,和文件操作函數 open()類
似,接下來對目錄的讀取和搜索都要使用此返回值。函數失敗則返回 NULL。
readdir()函數用來讀取目錄的信息,並返回一個結構體指針,該指針保存了目錄的相關信息。有
錯誤發生或者讀取到目錄文件尾則返回 NULL。

struct dirent 
{ 
  ino_t  d_ino;             /* inode number(此目錄進入點的 inode) */ 
  off_t  d_off;             /* offset to the next dirent(目錄開頭到進入點的位移) */ 
  unsigned short d_reclen;  /* length of this record(目錄名的長度) */ 
  unsigned char d_type;     /* type of file(所指的文件類型) */ 
  char   d_name[256];       /* filename(文件名) */ 
};

所有的dirent信息構成的鏈表(順序表)爲DIR,存在一個指針定位當前所在的鏈表結點。
每次readdir會移動到鏈表的下一結點,readdir讀取信息後,指針向後偏移,d_off指的是下一個結點的位置。經常用seekdir回到某個位置,而用telldir記錄一個位置。
seekdir()函數用來設置目錄流目前的讀取位置,再調用 readdir()函數時,便可以從此新位置開始
讀取。參數 offset 代表距離目錄文件開頭的偏移量。
telldir()函數用來返回目錄流當前的讀取位置。

獲取文件信息
可以通過 fstat 和 stat 函數獲取文件信息,調用完畢後,文件信息被填充到結構體 struct stat
變量中,函數原型爲:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
int stat(const char *file_name, struct stat *buf);    //文件名  stat 結構體指針 
int fstat(int fd, struct stat *buf);      //文件描述符   stat 結構體指針

結構體 stat 的定義爲:

struct stat { 
           dev_t         st_dev;      /*如果是設備,返回設備表述符,否則爲 0*/ 
           ino_t         st_ino;      /* i 節點號 */ 
           mode_t        st_mode;     /* 文件類型 */  無符號短整型 
           nlink_t       st_nlink;    /* 鏈接數 */ 
           uid_t         st_uid;      /* 屬主 ID */ 
           gid_t         st_gid;      /* 組 ID */ 
           dev_t         st_rdev;     /* 設備類型*/ 
           off_t         st_size;     /* 文件大小,字節表示 */ 
           blksize_t     st_blksize;  /* 塊大小*/ 
           blkcnt_t      st_blocks;   /* 塊數 */ 
           time_t        st_atime;    /* 最後訪問時間*/ 
           time_t        st_mtime;    /* 最後修改時間*/ 
           time_t        st_ctime;    /* 最後權限修改時間 */ 
    };

對於結構體的成員 st_mode,有一組宏可以進行文件類型的判斷:

S_ISLNK(mode)  判斷是否是符號鏈接 
S_ISREG(mode)  判斷是否是普通文件 
S_ISDIR(mode)  判斷是否是目錄 
S_ISCHR(mode)  判斷是否是字符型設備 
S_ISBLK(mode)  判斷是否是塊設備 
S_ISFIFO(mode) 判斷是否是命名管道 
S_ISSOCK(mode) 判斷是否是套接字 

案例:

#include<sys/stat.h> 
#include<unistd.h> 
int main() 
{ 
	struct stat buf; 
	stat (/etc/passwd”,&buf); 
	printf(/etc/passwd file size = %d \n”,buf.st_size);//st_size 可以得到文件大小 
	return 0;
} 
//如果用 fstat 函數實現,如下:  
int fd = open (/etc/passwd”,O_RDONLY);  //先獲得文件描述符
fstat(fd, &buf);  

案例:以樹形結構的形式輸出指定目錄下面的所有文件

#include <func.h>  //自定義的頭文件
int printDir(char *path, int width)
{
    DIR* dir;
    dir = opendir(path);
    ERROR_CHECK(dir, NULL, "opendir");  //自定義的宏
    struct dirent *p;
    char buf[1024]={0};
    while(p = readdir(dir))
    {
        if (!strcmp(p->d_name, ".")||!strcmp(p->d_name, ".."))
        {
            continue;
        }
        printf("%*s%s\n",width,"",p->d_name);
        sprintf(buf,"%s%s%s",path,"/",p->d_name);
        if(4 == p->d_type)
        {
            printDir(buf, width+4);
        }
    }
    closedir(dir);
}
int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);   //自定義的宏
    puts(argv[1]);
    printDir(argv[1], 4);
    return 0;
}

案例:傳遞任意一個目錄路徑,能夠顯示該目錄的ls -l的效果

#include <func.h>

void printState(char* argv)
{
    int ret;
    struct stat buf;
    ret = stat(argv,&buf);    //傳出參數
    //打印文件類型
    char file_type = '0';  
    if(S_ISLNK(buf.st_mode))         file_type = 'l';
    else if( S_ISREG(buf.st_mode) )  file_type = '-';
    else if( S_ISDIR(buf.st_mode) )  file_type = 'd';
    else if( S_ISCHR(buf.st_mode) )  file_type = 'c';
    else if( S_ISBLK(buf.st_mode) )  file_type = 'b';
    else if( S_ISFIFO(buf.st_mode) ) file_type = 'p';
    else if( S_ISSOCK(buf.st_mode) ) file_type = 's';
    printf("%c ",file_type);
    //打印文件權限
    char buffer[10]={0};
    char tmp_buf[] = "rwxrwxrwx";
    for(int i=0;i<9;i++)
    {
        if(buf.st_mode & (1<<(8-i)))
        {
            buffer[i] = tmp_buf[i];
        }
        else
        {
            buffer[i] = '-';
        }
    }
    printf("%s",buffer);
    printf("%ld %s %s %ld %s  ",buf.st_nlink,getpwuid(buf.st_uid)->pw_name,getgrgid(buf.st_gid)->gr_name
               ,buf.st_size,ctime(&buf.st_mtime));
}
int printDir(char *path)
{
    DIR* dir;
    dir = opendir(path);
    ERROR_CHECK(dir, NULL, "opendir");
    struct dirent *p;
    char buf[1024]={0};
   // char buf_t[1024]={0};
    while(p = readdir(dir))
    {
        if (!strcmp(p->d_name, ".")||!strcmp(p->d_name, ".."))
        {
            continue;
        }
        sprintf(buf,"%s%s%s",path,"/",p->d_name);
        char *argv = buf;
        printState(argv);
        printf("%s\n",p->d_name);
        // sprintf(buf,"%s%s%s",path,"/",p->d_name);
        if(4 == p->d_type)
        {
            printDir(buf);
        }
    }
    closedir(dir);
}
int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    printDir(argv[1]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章