unix下的文件和目錄詳解以及操作方法


前言:unix下一切東西都是文件,一共有7種不同的文件,前一篇博客已經講解的很清楚了,不懂的可以看看這里。當然,博主知道有些朋友比忙,沒時間看,那我就簡單點講講這7種文件都有哪些吧。

文件類型包括在stat結構的st_mode成員中,下面是這7種文件類型的判斷方法:
        宏                                     文件類型
S_ISREG(m)                 普通文件(is it a regular file?)
S_ISDIR(m)                  目錄文件(directory?)
S_ISCHR(m)                 字符特殊文件(character device?)
S_ISBLK(m)                  塊特殊文件(block device?)
S_ISFIFO(m)                管道或FIFO [FIFO (named pipe)?]
S_ISLNK(m)                  符號鏈接 [symbolic link? (Not in POSIX.1-1996.)]
S_ISSOCK(m)               套接字 [socket? (Not in POSIX.1-1996.)]

 

 

 

 

 

 

 

 

當然這些文件都是有訪問權限的,很巧這些權限也是在一個叫struct stat這個結構體中

結構體struct stat中的成員st_mode值包含了對文件的訪問權限位,任何類型的文件都有訪問權限(access permission)。每個文件有9個訪問權限,可以它們分為3類,u表示用戶(所有者)、g表示組、o表示其他

st_mode屏蔽                   含義
S_IRUSR                       用戶讀
S_IWUSR                      用戶寫
S_IXUSR                       用戶執行

S_IRGRP                         組讀
S_IWGRP                        組寫
S_IXGRP                       組執行

S_IROTH                       其他讀
S_IWOTH                      其他寫
S_ICOTH                       其他執行

 

 

 

 

 

 

 

 

 

 

 

 

 

那么問題來了既然有權限,我們怎么知道這些權限呢?當然這不是難事,一個access函數就可以解決問題了

函數描述:按實際用戶ID和實際組ID進行訪問權限測試
(1)頭文件
         #include <unistd.h>
(2)函數原型
          int access(const char *path, int amode);
(3)參數
         a、path:文件路徑
         b、amode:
                 F_OK:測試文件是否存在
                 R_OK:測試文件是否可讀
                 W_OK:測試文件是否可寫
                 X_OK:測試文件是否可執行
(4)返回值
          成功:0
          失敗:-1

 

 

 

 

 

 

 

 

 

 

 

 

這是access函數的具體用法的代碼(argv[1]必須是一個已經存在的文件):

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
    if(argc != 2)
    {
        printf("argc must equal to two!\n");
        exit(1);
    }

  if(access(argv[1],F_OK)) //判斷文件是否存在
    {
        printf("%s  not existence!\n",argv[1]);
        exit(1);
    }

  if(access(argv[1],R_OK)) //判斷文件是否可讀
    {
        printf("%s not read permission\n",argv[1]);
    }
    else
    {
        printf("%s  have read permission\n",argv[1]);
    }

  if(access(argv[1],W_OK))  //判斷文件是否可寫
    {
        printf("%s not write permission\n",argv[1]);
    }
    
    else
    {
        printf("%s  have write permission\n",argv[1]);
  }
  if(access(argv[1],X_OK)) //判斷文件是否可執行
    {
        printf("%s not execute permission\n",argv[1]);
    }
    else
    {
        printf("%s have execute permission\n",argv[1]);
    }

    return 0;
}
View Code

 在ubuntu下運行:

當然了既然有權限,那么我們在創建文件的時候文件權限也是可以自己控制的,umask函數用上場了


函數描述:為進程設置文件模式創建屏蔽字,並返回之前的值
(1)頭文件: #include <sys/stat.h>
(2)函數原型: mode_t umask(mode_t cmask);
(3)參數:
         cmask:(下面9個常量中的若干個按位或構成),例如:S_IRUSR|S_IRGRP //權限就為用戶讀和組讀
           st_mode屏蔽                    含義
             S_IRUSR                       用戶讀
             S_IWUSR                      用戶寫
             S_IXUSR                       用戶執行

             S_IRGRP                         組讀
             S_IWGRP                        組寫
             S_IXGRP                        組執行

             S_IROTH                       其他讀
             S_IWOTH                      其他寫
             S_ICOTH                       其他執行
(4)返回值:
          成功:之前的文件模式創建屏蔽字

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

代碼的具體用法如下:

#include <sys/stat.h>
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>

 #define RRR (S_IRUSR|S_IRGRP|S_IROTH) //設置文件權限為用戶讀、組讀、其他讀
 int main(int argc,char *argv[])
 {
     umask(0); //不設置文件屏蔽字
     creat("text",RRR); //以用戶讀、組讀、其他讀的權限創建文件text.txt //這里也可以用open
     
     umask(S_IRUSR|S_IRGRP); //創建用戶讀、組出屏蔽字
     creat("text1",RRR);   //最后創建出來的文件只有其他讀的權限 
     return 0;
 }
View Code

 既然文件可以創建,當然目錄也是可以創建的,mkdir函數就是為創建目錄而生的:

函數描述:創建一個空目錄,.和..自動創建
(1)頭文件
          #include <sys/stat.h>
(2)函數原型
          int mkdir(const char *path, mode_t mode);
(3)參數:
          a、path:文件名
          b、mode:是以下15種常量的按位或
                  mode                     含義
                S_ISUID               執行時設置用戶ID
                S_ISGID               執行時設置組ID
                S_ISVTX               保存正文(粘着位)

                S_IRWXU             用戶(所有者)、讀、寫和執行
                S_IRUSR              用戶(所有者)讀
                S_IWUSR             用戶(所有者)寫
                S_IXUSR              用戶(所有者)執行

                S_IRWXG             組讀、寫和執行
                S_IRGRP              組寫
                S_IWGRP             組讀
                S_IXGRP              組執行

                S_IRWXO            其他讀、寫和執行
                S_IROTH             其他讀
                S_IWOTH            其他寫
                S_IXOTH             其他執行
(4)返回值
         成功:0
         失敗:-1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

創建目錄的具體實現:

#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc,char *argv[])
{
    if(mkdir("test.txt",S_IWOTH|S_IRUSR|S_IRGRP) == -1) /*以其他寫、用戶讀、組讀權限創建一個空目錄*/
    {
        perror("mkdir");
        exit(1);
    }
    return 0;
}
View Code

 umask函數是在創建文時設置權限,那么在文件被創建之后還能修改權限嗎?這時候chmod函數就派上用處了

(1)頭文件        #include <sys/stat.h>

(2)函數原型     int chmod(const char *path, mode_t mode);

 (3)參數:

          a、path:文件路徑

          b、mode:跟上面midir函數中的成員mode一樣,其中的宏位或就可以了

 

 

 

 

 

 

 

 

改變文件權限的例子:

chmod("text",S_IRUSR|S_IRGRP|S_IROTH);    //把text文件的權限改為用戶讀、組讀、其他讀

 

 既然權限可以改變權限,當然改個名字也是沒問題的,用rename函數輕松解決問題:

(1)頭文件     #include <stdio.h>

(2)函數原型   int rename(const char *old, const char *new);

(3)參數:

          a、old:文件原來的名字

          b、new:新的名字

(4)返回值:

         成功:0

         失敗:-1

 

 

 

 

 

 

 

 

 

 改變文件名字的例子:

rename("text","hhtext"); //將名字為text的文件改為hhtext

 

其實文件中還有個小操作就是可以在任何位置截斷文件中的內容:

truncate("test",3);    //將文件test長度截斷為3字節

 

 

好了講了那么多關於文件的權限的東西,是時候講講怎么打開一個目錄和讀目錄中的的東西了:

 讀目錄中,要經過三步:打開目錄、讀目錄、關閉目錄,對應用到的函數分別為opendir、readdir、closedir。
 
 一、打開目錄
(1)頭文件
      #include <sys/types.h>
      #include <dirent.h>2)函數原型
      DIR *opendir(const char *name);
(3)參數
      name:目錄名
(4)返回值:
     成功:返回一個DIR*型的目錄流
     失敗:NULL
      
二、讀目錄
(1)頭文件
     #include <dirent.h>2)函數原型
     struct dirent *readdir(DIR *dirp);
(3)參數
      a、dirp:調用opendir函數后返回的DIR*類型的目錄流
(4)返回值:
     成功:返回一個(struct dirent)型的結構體
     下面是struct dirent結構體的具體內容
        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 supportedby all file system types */
               char           d_name[256]; 文件名 /* filename */
           };
        struct dirent中的成員d_type又有以下幾種類型:
           DT_BLK     塊設備  (This is a block device.)
           DT_CHR     字符設備(This is a character device.)
           DT_DIR     目錄( This is a directory.)
           DT_FIFO    命名管道或FIFO(This is a named pipe (FIFO).)
           DT_LNK     符號連接(This is a symbolic link.)
           DT_REG     普通文件(This is a regular file.)
           DT_SOCK    UNIX域套接字( This is a UNIX domain socket.)
           DT_UNKNOWN  未知類型(The file type is unknown.)
     讀完或者失敗都返回NULL

三、關閉目錄
(1)頭文件
      #include <sys/types.h>
      #include <dirent.h>2)函數原型
      int closedir(DIR *dirp);
(3)參數
     a、dirp:用opendir函數后返回的DIR*類型的目錄流
(4)返回值:
      成功:0
      失敗:-1
     
四、更改當前工作路徑
(1)頭文件    #include <unistd.h>2)函數原型  int chdir(const char *path);
(3)參數:
      a、path:需要更改的路徑
(4)返回值
      成功:0
      失敗:-1
例子:
    chdir("/test.txt"); //當前工作目錄更改到test.txt中
        
五、獲得當前工作目錄完整的絕對路徑
(1)頭文件     #include <unistd.h>2)函數原型   char *getcwd(char *buf, size_t size);
(3)參數:
     a、buf:存放絕對路徑的緩沖區
     b、size: 緩沖區的大小
(4)返回值:
     成功:返回當前工作目錄完整的絕對路徑
     失敗:NULL
例子:
     char buf[100];
     bzero(buf,sizeof(buf));
     if(getcwd(buf,sizeof(buf)) == NULL)
       {
         perror("getcwd");
         exit(1);
       }     
     

 打開一個目錄然后讀目錄中的文件並把文件名打印出來,具體代碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void open_file(char *name)
{
    DIR * entry; //opendir返回值
    struct dirent *ep; //readdir返回值
    char path_name[100];
    
    if((entry = opendir(name)) == NULL)
    {
        perror("opendir");
        exit(1);
    }
    
    while(1)
    {
       if((ep = readdir(entry)) == NULL)
       {
           break;
       }
       if(ep->d_name[0] == '.') //去掉隱藏文件
       {
           continue;
       }
      
        sprintf(path_name,"%s/%s",name,ep->d_name); //拼接兩個字符
        printf("%s\n",path_name); //輸出路徑
       
       if(ep->d_type & DT_DIR) //目錄  也可以用lstat/stat函數
       {   
           open_file(path_name); //遞歸打開下一目錄
       }
       
    }
    
    closedir(entry);
}
int main(int argc,char *argv[])
{
    if(argc != 2)
    {
        printf("argv[1] have to a directory!\n");
        exit(1);
    }
    open_file(argv[1]);
    return 0;
}
View Code

 運行程序的效果圖如下:

 最后來點小知識:

**每個文件系統所在的設備都有主、次設備號表示
**設備號所用的數據類型是基本系統數據類型dev_t
**我們通常可以使用兩個宏:major、minor來訪問主、次設備號
**系統中與每個文件名關聯的st_dev值是文件系統的設備號,該文件包括了這一文件名以及與其對應的i節點
**只有字特殊文件和塊特殊文件的才有st_rdev值。此值包括實際設備的設備號

 

 

 

具體代碼如下:

#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
    int i;
    struct stat buf;
    for(i=1;i<argc;i++)
    {
        printf("%s:",argv[i]);
        if(stat(argv[i],&buf) == -1){
            perror("stat");
            exit(1);
        }
        
        printf("dev = %d/%d",major(buf.st_dev),minor(buf.st_dev));
        //判斷是否是字特殊文件(S_ISCHR)塊特殊文件(S_ISCHR)
        if(S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)){
            printf(" (%s) rdev = %d/%d",
            (S_ISCHR(buf.st_mode)) ? "character" : "block",
            major(buf.st_rdev),minor(buf.st_rdev));
        }
        printf("\n");
    }
    return 0;
}
View Code

運行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM