Linux下文件的相關操作函數

1.文件的創建和讀寫

  當我們需要打開一個文件進行讀寫操作的時候,我們可以使用系統調用函數open.使用完成以後我們調用另外一個close函數進行關閉操作.

    int open(const char *pathname,int flags);

int open(const char*pathname,int flags,mode_t mode);

int close(int fd);

  open函數有兩個形式.其中pathname是我們要打開的文件名(包含路徑名稱,缺省是認爲在當前路徑下面).flags可以去下面的一個值或者是幾個值的組合.

    O_RDONLY  :以只讀的方式打開文件.

    O_WRONLY  :以只寫的方式打開文件.

    O_RDWR   :以讀寫的方式打開文件.

    O_APPEND  :以追加的方式打開文件.

O_CREAT :創建一個文件.

    O_EXEC   :如果使用了O_CREAT而且文件已經存在,就會發生一個錯誤.

    O_NOBLOCK  :以非阻塞的方式打開一個文件.

    O_TRUNC   :如果文件已經存在,則刪除文件的內容.

  前面三個標誌只能使用任意的一個.如果使用了O_CREATE標誌,那麼我們要使用open的第二種形式。還要指定mode標誌,用來表示文件的訪問權限。mode可以是以下情況的組合.

    -------------------------------------------------

    S_IRUSR 用戶可以讀 S_IWUSR 用戶可以寫

    S_IXUSR 用戶可以執行 S_IRWXU 用戶可以讀寫執行

    -------------------------------------------------

    S_IRGRP 組可以讀 S_IWGRP 組可以寫

    S_IXGRP 組可以執行 S_IRWXG 組可以讀寫執行

    -------------------------------------------------

    S_IROTH 其他人可以讀 S_IWOTH 其他人可以寫

    S_IXOTH 其他人可以執行 S_IRWXO 其他人可以讀寫執行

    -------------------------------------------------

    S_ISUID 設置用戶執行ID S_ISGID 設置組的執行ID

    -------------------------------------------------

  我們也可以用數字來代表各個位的標誌.Linux總共用5個數字來表示文件的各種權限.

    第一位表示設置用戶ID.

    第二位表示設置組ID,

    第三位表示用戶自己的權限位,

    第四位表示組的權限,

    最後一位表示其他人的權限.

    每個數字可以取1(執行權限),2(寫權限),4(讀權限),0(什麼也沒有)或者是這幾個值的和. 比如我們要創建一個用戶讀寫執行,組沒有權限,其他人讀執行的文件。設置用戶ID位那麼我們可以使用的模式是--1(設置用戶ID)0(組沒有設置)7(1+2+4)0(沒有權限,使用缺省)5(1+4)即10705:

    open("temp",O_CREAT,10705);

  如果我們打開文件成功,open會返回一個文件描述符.我們以後對文件的所有操作就可以對這個文件描述符進行操作了.

  當我們操作完成以後,我們要關閉文件了,只要調用close就可以了,其中fd是我們要關閉的文件描述符.

  文件打開了以後,我們就要對文件進行讀寫了.我們可以調用函數read和write進行文件的讀寫.

    ssize_t read(int fd, void *buffer,size_tcount);

ssize_t write(int fd, const void*buffer,size_t count);

  fd是我們要進行讀寫操作的文件描述符.

  buffer是我們要寫入文件內容或讀出文件內容的內存地址.

  count是我們要讀寫的字節數.

  對於普通的文件read從指定的文件(fd)中讀取count字節到buffer緩衝區中(記住我們必須提供一個足夠大的緩衝區),同時返回count.

  如果read讀到了文件的結尾或者被一個信號所中斷,返回值會小於count.

  如果是由信號中斷引起返回,而且沒有返回數據,read會返回-1,且設置errno爲EINTR.

  當程序讀到了文件結尾的時候,read會返回0.

  write從buffer中寫count字節到文件fd中,成功時返回實際所寫的字節數.

  下面我們學習一個實例,這個實例用來拷貝文件,該程序已檢測通過

  #include <unistd.h>

  #include <fcntl.h>

  #include <stdio.h>

  #include <sys/types.h>

  #include <sys/stat.h>

  #include <errno.h>

  #include <string.h>

  

  #define BUFFER_SIZE 1024

  

  int main(int argc,char **argv)

  {

    

    int from_fd,to_fd;

    int bytes_read,bytes_write;

    char buffer[BUFFER_SIZE];

    char *ptr;

    

    if(argc!=3)

    {

      fprintf(stderr,"Usage:%s fromfiletofile\n\a",argv[0]);

      exit(1);

    }

    

    if((from_fd=open(argv[1],O_RDONLY))==-1)

    {

      fprintf(stderr,"Open %sError:%s\n",argv[1],strerror(errno));

      exit(1);

    }

    

    if((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1)

    {

      fprintf(stderr,"Open %sError:%s\n",argv[2],strerror(errno));

      exit(1);

    }

    

    while(bytes_read=read(from_fd,buffer,BUFFER_SIZE))

    {

      if((bytes_read==-1)&&(errno!=EINTR)) break;

      else if(bytes_read>0)

      {

        ptr=buffer;

        while(bytes_write=write(to_fd,ptr,bytes_read))

        {

          if((bytes_write==-1)&&(errno!=EINTR))break;

          else if(bytes_write==bytes_read) break;

          else if(bytes_write>0)

          {

            ptr+=bytes_write;

            bytes_read-=bytes_write;

          }

        }

        if(bytes_write==-1)break;

      }

    }

    close(from_fd);

    close(to_fd);

    exit(0);

  }

 

2.文件的各個屬性

  文件具有各種各樣的屬性,除了我們上面所知道的文件權限以外,文件還有創建時間,大小等等屬性.有時侯我們要判斷文件是否可以進行某種操作(讀,寫等等).這個時候我們可以使用access函數.

    int access(const char *pathname,int mode);

  pathname是文件名稱,

  mode是我們要判斷的屬性.可以取以下值或者是他們的組合.

  R_OK文件可以讀,W_OK文件可以寫,X_OK文件可以執行,F_OK文件存在.

  當我們測試成功時,函數返回0,否則如果有一個條件不符時,返回-1.

  如果我們要獲得文件的其他屬性,我們可以使用函數stat或者fstat.

    int stat(const char *file_name,struct stat *buf);

    int fstat(int filedes,struct stat *buf);

    

  struct stat

  {

    dev_t st_dev;       /* 設備 */

    ino_t st_ino;       /* 節點 */

    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_off;       /* 文件字節數 */

    unsigned long st_blksize; /* 塊大小 */

    unsigned long st_blocks;  /* 塊數 */

    time_t st_atime;      /* 最後一次訪問時間 */

    time_t st_mtime;      /* 最後一次修改時間 */

    time_t st_ctime;      /* 最後一次改變時間(指屬性) */

  };

  stat用來判斷沒有打開的文件,而fstat用來判斷打開的文件.我們使用最多的屬性是st_mode.通過着屬性我們可以判斷給定的文件是一個普通文件還是一個目錄,連接等等.可以使用下面幾個宏來判斷.

  S_ISLNK(st_mode):是否是一個連接.

  S_ISREG是否是一個常規文件.

  S_ISDIR是否是一個目錄.

  S_ISCHR是否是一個字符設備.

  S_ISBLK是否是一個塊設備.

  S_ISFIFO是否是一個FIFO文件.

  S_ISSOCK是否是一個SOCKET文件.

 

3.目錄文件的操作

  在我們編寫程序的時候,有時候會要得到我們當前的工作路徑。C庫函數提供了getcwd來解決這個問題。

    char *getcwd(char *buffer,size_t size);

  我們提供一個size大小的buffer,getcwd會把我們當前的路徑考到buffer中.如果buffer太小,函數會返回-1和一個錯誤號.

  Linux提供了大量的目錄操作函數,我們學習幾個比較簡單和常用的函數:

    int mkdir(const char *path,mode_tmode);

    DIR *opendir(const char *path);

    struct dirent *readdir(DIR *dir);

    void rewinddir(DIR *dir);

    off_t telldir(DIR *dir);

    void seekdir(DIR *dir,off_t off);

    int closedir(DIR *dir);

 

    struct dirent

    {

      long d_ino;

      off_t d_off;

      unsigned short d_reclen;

      char d_name[NAME_MAX+1]; /* 文件名稱 */

    }

  mkdir:很容易就是我們創建一個目錄.

  opendir:打開一個目錄爲以後讀做準備.

  readdir:讀一個打開的目錄.

  rewinddir:是用來重讀目錄的,和我們學的rewind函數一樣.

  closedir:是關閉一個目錄.

  telldir和seekdir類似與ftell和fseek函數.

 

  下面我們開發一個小程序,這個程序有一個參數.如果這個參數是一個文件名,我們輸出這個文件的大小和最後修改的時間,如果是一個目錄我們輸出這個目錄下所有文件的大小和修改時間.

  static int get_file_size_time(const char *filename)

  {

    struct stat statbuf;

    if(stat(filename,&statbuf)==-1)

    {

      printf("Get stat on %s Error:%s\n",

        filename,strerror(errno));

      return(-1);

    }

    if(S_ISDIR(statbuf.st_mode))return(1);

    if(S_ISREG(statbuf.st_mode))

      printf("%s size:%ld bytes\tmodified at %s",

        filename,statbuf.st_size,ctime(&statbuf.st_mtime));

    return(0);

  }

 

  int main(int argc,char **argv)

  {

    DIR *dirp;

    struct dirent *direntp;

    int stats;

    if(argc!=2)

    {

      printf("Usage:%sfilename\n\a",argv[0]);

      exit(1);

    }

    if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))

  exit(1);

    if((dirp=opendir(argv[1]))==NULL)

    {

      printf("Open Directory %s Error:%s\n",

        argv[1],strerror(errno));

      exit(1);

    }

    while((direntp=readdir(dirp))!=NULL)

      if(get_file_size_time(direntp-br> closedir(dirp);

        exit(1);

  }

 

4.管道文件

  Linux提供了許多的過濾和重定向程序,比如more cat等等.還提供了< > | <<等等重定向操作符.在這些過濾和重定向程序當中,都用到了管道這種特殊的文件.系統調用pipe可以創建一個管道.

    int pipe(int fildes[2]);

  pipe調用可以創建一個管道(通信緩衝區).當調用成功時,我們可以訪問文件描述符fildes[0],fildes[1].其中fildes[0]是用來讀的文件描述符,而fildes[1]是用來寫的文件描述符.

  在實際使用中我們是通過創建一個子進程,然後一個進程寫,一個進程讀來使用的.

 

  #define BUFFER 255

  

  int main(int argc,char **argv)

  {

    char buffer[BUFFER+1];

    int fd[2];

    if(argc!=2)

    {

      fprintf(stderr,"Usage:%sstring\n\a",argv[0]);

      exit(1);

    }

    if(pipe(fd)!=0)

    {

      fprintf(stderr,"PipeError:%s\n\a",strerror(errno));

      exit(1);

    }

    if(fork()==0)

    {

      close(fd[0]);

      printf("Child[%d] Write topipe\n\a",getpid());

      snprintf(buffer,BUFFER,"%s",argv[1]);

      write(fd[1],buffer,strlen(buffer));

      printf("Child[%d] Quit\n\a",getpid());

      exit(0);

    }

    else

    {

      close(fd[1]);

      printf("Parent[%d] Read frompipe\n\a",getpid());

      memset(buffer,'\0',BUFFER+1);

      read(fd[0],buffer,BUFFER);

      printf("Parent[%d]Read:%s\n",getpid(),buffer);

      exit(1);

    }

  }

 

  爲了實現重定向操作,我們需要調用另外一個函數dup2.

    int dup2(int oldfd,int newfd);

  dup2將用oldfd文件描述符來代替newfd文件描述符,同時關閉newfd文件描述符.也就是說,所有向newfd操作都轉到oldfd上面.下面我們學習一個例子,這個例子將標準輸出重定向到一個文件.

 

  #define BUFFER_SIZE 1024

  

  int main(int argc,char **argv)

  {

    int fd;

    char buffer[BUFFER_SIZE];

    if(argc!=2)

    {

      fprintf(stderr,"Usage:%soutfilename\n\a",argv[0]);

      exit(1);

    }

    if((fd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1)

    {

      fprintf(stderr,"Open %s Error:%s\n\a",argv[1],strerror(errno));

      exit(1);

    }

    if(dup2(fd,STDOUT_FILENO)==-1)

    {

      fprintf(stderr,"Redirect Standard OutError:%s\n\a",strerror(errno));

      exit(1);

    }

    fprintf(stderr,"Now,please input string");

    fprintf(stderr,"(To quit use CTRL+D)\n");

    while(1)

    {

      fgets(buffer,BUFFER_SIZE,stdin);

      if(feof(stdin))break;

      write(STDOUT_FILENO,buffer,strlen(buffer));

    }

    exit(0);

  }

 

5.其他文件操作函數

  

  5.01 access 判斷是否具有存取文件的權限

  頭文 件

  #include<unistd.h>

  定  義

  int access(const char * pathname,int mode);

  函數說明

  access()會檢查是否可以讀/寫某一已存在的文件。參數mode有幾種情況組合,R_OK,W_OK,X_OK 和F_OK。R_OK,W_OK與X_OK用來檢查文件是否具有讀取、寫入和執行的權限。F_OK則是用來判斷該文件是否存在。由於access()只作權限的核查,並不理會文件形態或文件內容,因此,如果一目錄表示爲"可寫入",表示可以在該目錄中建立新文件等操作,而非意味此目錄可以被當做文件處理。例如,你會發現DOS的文件都具有"可執行"權限,但用execve()執行時則會失敗。

  返回 值

  若所有欲查覈的權限都通過了檢查則返回0值,表示成功,只要有一權限被禁止則返回-1。

  錯誤代碼

  EACCESS   參數pathname 所指定的文件不符合所要求測試的權限。

  EROFS    欲測試寫入權限的文件存在於只讀文件系統內。

  EFAULT   參數pathname指針超出可存取內存空間。

  EINVAL   參數mode 不正確。

  ENAMETOOLONG參數pathname太長。

  ENOTDIR   參數pathname爲一目錄。

  ENOMEM   核心內存不足

  ELOOP    參數pathname有過多符號連接問題。

  EIO     I/O 存取錯誤。

  附加說明

  使用access()作用戶認證方面的判斷要特別小心,例如在access()後再做open()的空文件可能會造成系統安全上的問題。

  範  例

  /* 判斷是否允許讀取/etc/passwd */

  #include<unistd.h>

  int main()

  {

    if (access("/etc/passwd",R_OK) = =0)

    printf("/etc/passwd can be read\n");

  }

 

  5.02 alphasort 依字母順序排序目錄結構

  頭文 件

  #include<dirent.h>

  定  義

  int alphasort(const struct dirent **a,const structdirent **b);

  函數說明

  alphasort()爲scandir()最後調用qsort()函數時傳給qsort()作爲判斷的函數,詳細說明請參考scandir()及qsort()。

  函數說明

  參考qsort()。

  範  例

  /* 讀取/目錄下所有的目錄結構,並依字母順序排列*/

  main()

  {

    struct dirent **namelist;

    int i,total;

    total = scandir("/",&namelist,0,alphasort);

    if(total <0)

      perror("scandir");

    else

    {

      for(i=0;i<total;i++)

        printf("%s\n",namelist[i]->d_name);

      printf("total = %d\n",total);

    }

  }

 

  5.03 chdir 改變當前的工作目錄

  頭文 件

  #include<unistd.h>

  定義函數

  int chdir(const char * path);

  函數說明

  chdir()用來將當前的工作目錄改變成以參數path所指的目錄。

  函數說明

  執行成功則返回0,失敗返回-1,errno爲錯誤代碼。

  範  例

  #include<unistd.h>

  main()

  {

    chdir("/tmp");

    printf("current working directory:%s\n",getcwd(NULL,NULL));

  }

 

  5.04 chmod 改變文件的權限

  頭文 件

  #include<sys/types.h>

  #include<sys/stat.h>

  定  義

    int chmod(const char * path,mode_t mode);

  函數說明

  chmod()會依參數mode 權限來更改參數path 指定文件的權限。

  參數 mode 有下列數種組合

    S_ISUID 04000 文件的(set user-id on execution)位

    S_ISGID 02000 文件的(set group-id on execution)位

    S_ISVTX 01000 文件的sticky位

    S_IRUSR(S_IREAD) 00400 文件所有者具可讀取權限

    S_IWUSR(S_IWRITE)00200 文件所有者具可寫入權限

    S_IXUSR(S_IEXEC) 00100 文件所有者具可執行權限

    S_IRGRP 00040 用戶組具可讀取權限

    S_IWGRP 00020 用戶組具可寫入權限

    S_IXGRP 00010 用戶組具可執行權限

    S_IROTH 00004 其他用戶具可讀取權限

    S_IWOTH 00002 其他用戶具可寫入權限

    S_IXOTH 00001 其他用戶具可執行權限

  只有該文件的所有者或有效用戶識別碼爲0,纔可以修改該文件權限。基於系統安全,如果欲將數據寫入一執行文件,而該執行文件具有S_ISUID 或S_ISGID 權限,則這兩個位會被清除。如果一目錄具有S_ISUID 位權限,表示在此目錄下只有該文件的所有者或root可以刪除該文件。

  函數說明

  權限改變成功返回0,失敗返回-1,錯誤原因存於errno。

  錯誤代碼

  EPERM      進程的有效用戶識別碼與欲修改權限的文件擁有者不同,而且也不具root權限。

  EACCESS     參數path所指定的文件無法存取。

  EROFS      欲寫入權限的文件存在於只讀文件系統內。

  EFAULT     參數path指針超出可存取內存空間。

  EINVAL     參數mode不正確

  ENAMETOOLONG  參數path太長

  ENOENT     指定的文件不存在

  ENOTDIR     參數path路徑並非一目錄

  ENOMEM     核心內存不足

  ELOOP      參數path有過多符號連接問題。

  EIO       I/O存取錯誤

  範  例

  /* 將/etc/passwd 文件權限設成S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH */

  #include<sys/types.h>

  #include<sys/stat.h>

  main()

  {

    chmod("/etc/passwd",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

  }

 

  5.05 chown 改變文件的所有者

  頭文 件

  #include<sys/types.h>

  #include<unistd.h>

  定  義

  int chown(const char * path, uid_t owner,gid_t group);

  函數說明

  chown()會將參數path指定文件的所有者變更爲參數owner代表的用戶,而將該文件的組變更爲參數group組。如果參數owner或group爲-1,對應的所有者或組不會有所改變。root與文件所有者皆可改變文件組,但所有者必須是參數group組的成員。當root用chown()改變文件所有者或組時,該文件若具有S_ISUID或S_ISGID權限,則會清除此權限位,此外如果具有S_ISGID權限但不具S_IXGRP位,則該文件會被強制鎖定,文件模式會保留。

  函數說明

  成功則返回0,失敗返回-1,錯誤原因存於errno。

  錯誤代碼

  參考chmod()。

  範  例

  /* 將/etc/passwd 的所有者和組都設爲root */

  #include<sys/types.h>

  #include<unistd.h>

  main()

  {

    chown("/etc/passwd",0,0);

  }

 

  5.06 chroot 改變根目錄

  頭文 件

  #include<unistd.h>

  定  義

  int chroot(const char * path);

  函數說明

  chroot()用來改變根目錄爲參數path 所指定的目錄。只有超級用戶才允許改變根目錄,子進程將繼承新的根目錄。

  函數說明

  調用成功則返回0,失敗則返-1,錯誤代碼存於errno。

  

  錯誤代碼

  EPERM  權限不足,無法改變根目錄。

  EFAULT 參數path指針超出可存取內存空間。

  ENAMETOOLONG  參數path太長。

  ENOTDIR 路徑中的目錄存在但卻非真正的目錄。

  EACCESS 存取目錄時被拒絕

  ENOMEM 核心內存不足。

  ELOOP  參數path有過多符號連接問題。

  EIO   I/O存取錯誤。

  範  例

  /* 將根目錄改爲/tmp ,並將工作目錄切換至/tmp */

  #include<unistd.h>

  main()

  {

    chroot("/tmp");

    chdir("/");

  }

  

  5.07 closedir  關閉目錄

  頭文 件

  #include<sys/types.h>

  #include<dirent.h>

  定  義

  int closedir(DIR *dir);

  函數說明

  closedir()關閉參數dir所指的目錄流。

  函數說明

  關閉成功則返回0,失敗返回-1,錯誤原因存於errno 中。

  錯誤代碼

  EBADF  參數dir爲無效的目錄流

    範  例

  參考readir()。

  

  5.08 fchdir 改變當前的工作目錄

  頭文 件

  #include<unistd.h>

  定  義

  int fchdir(int fd);

  函數說明

  fchdir()用來將當前的工作目錄改變成以參數fd 所指的文件描述詞。

  函數說明

  行成功則返回0,失敗返回-1,errno爲錯誤代碼。

  附加說明

  

  範  例

  #include<sys/types.h>

  #include<sys/stat.h>

  #include<fcntl.h>

  #include<unistd.h>

  main()

  {

    int fd;

    fd = open("/tmp",O_RDONLY);

    fchdir(fd);

    printf("current working directory : %s\n",getcwd(NULL,NULL));

    close(fd);

  }

  

  5.09 fchmod 改變文件的權限

  頭文 件

  #include<sys/types.h>

  #include<sys/stat.h>

  定  義

  int fchmod(int fildes,mode_t mode);

  函數說明

  fchmod()會依參數mode權限來更改參數fildes所指文件的權限。參數fildes爲已打開文件的文件描述詞。參數mode請參考chmod()。

  函數說明

  權限改變成功則返回0,失敗返回-1,錯誤原因存於errno。

  錯誤原因

  EBADF  參數fildes爲無效的文件描述詞。

  EPERM  進程的有效用戶識別碼與欲修改權限的文件所有者不同,而且也不具root權限。

  EROFS  欲寫入權限的文件存在於只讀文件系統內。

  EIO   I/O存取錯誤。

  範  例

  #include<sys/stat.h>

  #include<fcntl.h>

  main()

  {

    int fd;

    fd = open ("/etc/passwd",O_RDONLY);

    fchmod(fd,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

    close(fd);

  }

  

  5.10  fchown 改變文件的所有者

  頭文 件

  #include<sys/types.h>

  #include<unistd.h>

  定  義

  int fchown(int fd,uid_t owner,gid_t group);

  函數說明

  fchown()會將參數fd指定文件的所有者變更爲參數owner代表的用戶,而將該文件的組變更爲參數group組。如果參數owner或group爲-1,對映的所有者或組有所改變。參數fd 爲已打開的文件描述詞。當root用fchown()改變文件所有者或組時,該文件若具S_ISUID或S_ISGID權限,則會清除此權限位。

  函數說明

  成功則返回0,失敗則返回-1,錯誤原因存於errno。

  錯誤代碼

  EBADF  參數fd文件描述詞爲無效的或該文件已關閉。

  EPERM  進程的有效用戶識別碼與欲修改權限的文件所有者不同,而且也不具root權限,或是參數owner、group不正確。

  EROFS  欲寫入的文件存在於只讀文件系統內。

  ENOENT 指定的文件不存在

  EIO   I/O存取錯誤

  範  例

  #include<sys/types.h>

  #include<unistd.h>

  #include<fcntl.h>

  main()

  {

    int fd;

    fd = open ("/etc/passwd",O_RDONLY);

    chown(fd,0,0);

    close(fd);

  }

  

  5.11  fstat  由文件描述詞取得文件狀態

  頭文 件

  #include<sys/stat.h>

  #include<unistd.h>

  定  義

  int fstat(int fildes,struct stat *buf);

  函數說明

  fstat()用來將參數fildes所指的文件狀態,複製到參數buf所指的結構中(struct stat)。Fstat()與stat()作用完全相同,不同處在於傳入的參數爲已打開的文件描述詞。詳細內容請參考stat()。

  函數說明

  執行成功則返回0,失敗返回-1,錯誤代碼存於errno。

  範  例

  #include<sys/stat.h>

  #include<unistd.h>

  #include<fcntk.h>

  main()

  {

    struct stat buf;

    int fd;

    fd = open ("/etc/passwd",O_RDONLY);

    fstat(fd,&buf);

    printf("/etc/passwd file size +%d\n",buf.st_size);

  }

  

  5.12  ftruncate  改變文件大小

  頭文 件

  #include<unistd.h>

  定  義

  int ftruncate(int fd,off_t length);

  函數說明

  ftruncate()會將參數fd指定的文件大小改爲參數length指定的大小。參數fd爲已打開的文件描述詞,而且必須是以寫入模式打開的文件。如果原來的文件大?炔問齦ength大,則超過的部分會被刪去。

  函數說明

  執行成功則返回0,失敗返回-1,錯誤原因存於errno。

  錯誤代碼

  EBADF  參數fd文件描述詞爲無效的或該文件已關閉。

  EINVAL 參數fd 爲一socket 並非文件,或是該文件並非以寫入模式打開。

  

  5.13  getcwd 取得當前的工作目錄

  頭文 件

  #include<unistd.h>

  定  義

  char * getcwd(char * buf,size_t size);

  函數說明

  getcwd()會將當前的工作目錄絕對路徑複製到參數buf所指的內存空間,參數size爲buf的空間大小。在調用此函數時,buf所指的內存空間要足夠大,若工作目錄絕對路徑的字符串長度超過參數size大小,則回值NULL,errno的值則爲ERANGE。倘若參數buf爲NULL,getcwd()會依參數size的大小自動配置內存(使用malloc()),如果參數size也爲0,則getcwd()會依工作目錄絕對路徑的字符串程度來決定所配置的內存大小,進程可以在使用完此字符串後利用free()來釋放此空間。

  函數說明

  執行成功則將結果複製到參數buf所指的內存空間,或是返回自動配置的字符串指針。失敗返回NULL,錯誤代碼存於errno。

  範  例

  #include<unistd.h>

  main()

  {

    char buf[80];

    getcwd(buf,sizeof(buf));

    printf("current working directory :%s\n",buf);

  }

  

  5.14  link  建立文件連接

  頭文 件

  #include<unistd.h>

  定  義

  int link (const char * oldpath,const char * newpath);

  函數說明

  link()以參數newpath指定的名稱來建立一個新的連接(硬連接)到參數oldpath所指定的已存在文件。如果參數newpath指定的名稱爲一已存在的文件則不會建立連接。

  函數說明

  成功則返回0,失敗返回-1,錯誤原因存於errno。

  附加說明

  link()所建立的硬連接無法跨越不同文件系統,如果需要請改用symlink()。

  錯誤代碼

  EXDEV  參數oldpath與newpath不是建立在同一文件系統。

  EPERM  參數oldpath與newpath所指的文件系統不支持硬連接

  EROFS  文件存在於只讀文件系統內

  EFAULT 參數oldpath或newpath 指針超出可存取內存空間。

  ENAMETOLLONG  參數oldpath或newpath太長

  ENOMEM 核心內存不足

  EEXIST 參數newpath所指的文件名已存在。

  EMLINK 參數oldpath所指的文件已達最大連接數目。

  ELOOP  參數pathname有過多符號連接問題

  ENOSPC 文件系統的剩餘空間不足。

  EIO   I/O存取錯誤。

  範  例

  /* 建立/etc/passwd 的硬連接爲pass */

  #include<unistd.h>

  main()

  {

    link("/etc/passwd","pass");

  }

  

  5.15  lstat  由文件描述詞取得文件狀態

  頭文 件

  #include<sys/stat.h>

  #include<unistd.h>

  定  義

  int lstat (const char * file_name.struct stat * buf);

  函數說明

  lstat()與stat()作用完全相同,都是取得參數file_name所指的文件狀態,其差別在於,當文件爲符號連接時,lstat()會返回該link本身的狀態。詳細內容請參考stat()。

  函數說明

  執行成功則返回0,失敗返回-1,錯誤代碼存於errno。

  範  例

  參考stat()。

  

  5.16  opendir 打開目錄

  頭文 件

  #include<sys/types.h>

  #include<dirent.h>

  定  義

  DIR * opendir(const char * name);

  函數說明

  opendir()用來打開參數name指定的目錄,並返回DIR*形態的目錄流,和open()類似,接下來對目錄的讀取和搜索都要使用此返回值。

  函數說明

  成功則返回DIR* 型態的目錄流,打開失敗則返回NULL。

  錯誤代碼

  EACCESS 權限不足

  EMFILE 已達到進程可同時打開的文件數上限。

  ENFILE 已達到系統可同時打開的文件數上限。

  ENOTDIR 參數name非真正的目錄

  ENOENT 參數name 指定的目錄不存在,或是參數name 爲一空字符串。

  ENOMEM 核心內存不足。

  

  5.17  readdir 讀取目錄

  頭文 件

  #include<sys/types.h>

  #include<dirent.h>

  定  義

  struct dirent * readdir(DIR * dir);

  函數說明

  readdir()返回參數dir目錄流的下個目錄進入點。

  結構定義

  struct dirent

  {

    ino_t d_ino;

    ff_t d_off;

    signed short int d_reclen;

    unsigned char d_type;

    har d_name[256;

  };

  d_ino    此目錄進入點的inode

  d_off    目錄文件開頭至此目錄進入點的位移

  d_reclen  d_name的長度,不包含NULL字符

  d_type   d_name 所指的文件類型

  d_name   文件名

  函數說明

  成功則返回下個目錄進入點。有錯誤發生或讀取到目錄文件尾則返回NULL。

  錯誤代碼

  EBADF  參數dir爲無效的目錄流。

  範  例

  #include<sys/types.h>

  #include<dirent.h>

  #include<unistd.h>

  main()

  {

    DIR * dir;

    struct dirent * ptr;

    int i;

    dir =opendir("/etc/rc.d");

    while((ptr = readdir(dir))!=NULL)

    {

      printf("d_name: %s\n",ptr->d_name);

    }

    closedir(dir);

  }

  

  5.18  readlink  取得符號連接所指的文件

  頭文 件

  #include<unistd.h>

  定  義

  int readlink(const char * path ,char * buf,size_tbufsiz);

  函數說明

  readlink()會將參數path的符號連接內容存到參數buf所指的內存空間,返回的內容不是以NULL作字符串結尾,但會將字符串的字符數返回。若參數bufsiz小於符號連接的內容長度,過長的內容會被截斷。

  函數說明

  執行成功則傳符號連接所指的文件路徑字符串,失敗則返回-1,錯誤代碼存於errno。

  錯誤代碼

  EACCESS 取文件時被拒絕,權限不夠

  EINVAL 參數bufsiz 爲負數

  EIO   I/O存取錯誤。

  ELOOP  欲打開的文件有過多符號連接問題。

  ENAMETOOLONG  參數path的路徑名稱太長

  ENOENT 參數path所指定的文件不存在

  ENOMEM 核心內存不足

  ENOTDIR 參數path路徑中的目錄存在但卻非真正的目錄。

  

  5.19  remove 刪除文件

  頭文 件

  #include<stdio.h>

  定  義

  int remove(const char * pathname);

  函數說明

  remove()會刪除參數pathname指定的文件。如果參數pathname爲一文件,則調用unlink()處理,若參數pathname爲一目錄,則調用rmdir()來處理。請參考unlink()與rmdir()。

  函數說明

  成功則返回0,失敗則返回-1,錯誤原因存於errno。

  錯誤代碼

  EROFS  欲寫入的文件存在於只讀文件系統內

  EFAULT 參數pathname指針超出可存取內存空間

  ENAMETOOLONG  參數pathname太長

  ENOMEM 核心內存不足

  ELOOP  參數pathname有過多符號連接問題

  EIO   I/O存取錯誤。

  

  5.20  rename 更改文件名稱或位置

  頭文 件

  #include<stdio.h>

  定  義

  int rename(const char * oldpath,const char * newpath);

  函數說明

  rename()會將參數oldpath 所指定的文件名稱改爲參數newpath所指的文件名稱。若newpath所指定的文件已存在,則會被刪除。

  函數說明

  執行成功則返回0,失敗返回-1,錯誤原因存於errno

  範  例

  /* 設計一個DOS下的rename指令rename 舊文件名新文件名*/

  #include <stdio.h>

  void main(int argc,char **argv)

  {

    if(argc<3)

    {

      printf("Usage: %s old_name new_name\n",argv[0]);

      return;

    }

    printf("%s=>%s",argc[1],argv[2]);

    if(rename(argv[1],argv[2]<0)

      printf("error!\n");

    else

      printf("ok!\n");

  }

  

  5.21  rewinddir  重設讀取目錄的位置爲開頭位置

  頭文 件

  #include<sys/types.h>

  #include<dirent.h>

  定  義

  void rewinddir(DIR *dir);

  函數說明

  rewinddir()用來設置參數dir 目錄流目前的讀取位置爲原來開頭的讀取位置。

  錯誤代碼

  EBADF dir爲無效的目錄流

  範  例

  #include<sys/types.h>

  #include<dirent.h>

  #include<unistd.h>

  main()

  {

    DIR * dir;

    struct dirent *ptr;

    dir = opendir("/etc/rc.d");

    while((ptr = readdir(dir))!=NULL)

    {

      printf("d_name :%s\n",ptr->d_name);

    }

    rewinddir(dir);

    printf("readdir again!\n");

    while((ptr = readdir(dir))!=NULL)

    {

      printf("d_name: %s\n",ptr->d_name);

    }

    closedir(dir);

  }

  

  5.22  seekdir 設置下回讀取目錄的位置

  頭文 件

  #include<dirent.h>

  定  義

  void seekdir(DIR * dir,off_t offset);

  函數說明

  seekdir()用來設置參數dir目錄流目前的讀取位置,在調用readdir()時便從此新位置開始讀取。參數offset 代表距離目錄文件開頭的偏移量。

  錯誤代碼

  EBADF  參數dir爲無效的目錄流

  範  例

  #include<sys/types.h>

  #include<dirent.h>

  #include<unistd.h>

  main()

  {

    DIR * dir;

    struct dirent * ptr;

    int offset,offset_5,i=0;

    dir=opendir("/etc/rc.d");

    while((ptr = readdir(dir))!=NULL)

    {

      offset = telldir(dir);

      if(++i = =5) offset_5 =offset;

      printf("d_name :%s offset :%d\n",ptr->d_name,offset);

    }

    seekdir(dir offset_5);

    printf("Readdir again!\n");

    while((ptr = readdir(dir))!=NULL)

    {

      offset = telldir(dir);

      printf("d_name :%s offset :%d\n",ptr->d_name.offset);

    }

    closedir(dir);

  }

  

  5.23  stat  取得文件狀態

  頭文 件

  #include<sys/stat.h>

  #include<unistd.h>

  定  義

  int stat(const char * file_name,struct stat *buf);

  函數說明

  stat()用來將參數file_name所指的文件狀態,複製到參數buf所指的結構中。

  結構定義

  struct stat

  {

    dev_t st_dev; /*device*/

    ino_t st_ino; /*inode*/

    mode_t st_mode; /*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 type */

    off_t st_size; /*total size, in bytes*/

    unsigned long st_blksize; /*blocksize for filesystemI/O */

    unsigned long st_blocks; /*number of blocksallocated*/

    time_t st_atime; /* time of lastaccess*/

    time_t st_mtime; /* time of last modification */

    time_t st_ctime; /* time of last change */

  };

  st_dev   文件的設備編號

  st_ino   文件的i-node

  st_mode   文件的類型和存取的權限

  st_nlink  連到該文件的硬連接數目,剛建立的文件值爲1。

  st_uid   文件所有者的用戶識別碼

  st_gid   文件所有者的組識別碼

  st_rdev   若此文件爲裝置設備文件,則爲其設備編號

  st_size   文件大小,以字節計算

  st_blksize 文件系統的I/O 緩衝區大小。

  st_blocks  佔用文件區塊的個數,每一區塊大小爲512 個字節。

  st_atime  文件最近一次被存取或被執行的時間,一般只有在用mknod、utime、read、write與tructate時改變。

  st_mtime  文件最後一次被修改的時間,一般只有在用mknod、utime和write時纔會改變

  st_ctime  i-nod最近一次被更改的時間,此參數會在文件所有者、組、權限被更改時更新先前所描述的

  st_mode 則定義了下列數種情況

  S_IFMT   0170000   文件類型的位遮罩

  S_IFSOCK  0140000   scoket

  S_IFLNK   0120000   符號連接

  S_IFREG   0100000   一般文件

  S_IFBLK   0060000   區塊裝置

  S_IFDIR   0040000   目錄

  S_IFCHR   0020000   字符裝置

  S_IFIFO   0010000   先進先出

  S_ISUID   04000    文件的(set user-id on execution)位

  S_ISGID   02000    文件的(set group-id on execution)位

  S_ISVTX   01000    文件的sticky位

  S_IRUSR(S_IREAD)  00400  文件所有者具可讀取權限

  S_IWUSR(S_IWRITE)  00200  文件所有者具可寫入權限

  S_IXUSR(S_IEXEC)  00100  文件所有者具可執行權限

  S_IRGRP   00040    用戶組具可讀取權限

  S_IWGRP   00020    用戶組具可寫入權限

  S_IXGRP   00010    用戶組具可執行權限

  S_IROTH   00004    其他用戶具可讀取權限

  S_IWOTH   00002    其他用戶具可寫入權限

  S_IXOTH   00001    其他用戶具可執行權限

  上述的文件類型在POSIX 中定義了檢查這些類型的宏定義

  S_ISLNK(st_mode)    判斷是否爲符號連接

  S_ISREG(st_mode)    是否爲一般文件

  S_ISDIR(st_mode)    是否爲目錄

  S_ISCHR(st_mode)    是否爲字符裝置文件

  S_ISBLK(s3e)      是否爲先進先出

  S_ISSOCK(st_mode)    是否爲socket

  若一目錄具有sticky 位(S_ISVTX),則表示在此目錄下的文件只能被該文件所有者、此目錄所有者或root來刪除或改名。

  函數說明

  執行成功則返回0,失敗返回-1,錯誤代碼存於errno

  錯誤代碼

  ENOENT 參數file_name指定的文件不存在

  ENOTDIR 路徑中的目錄存在但卻非真正的目錄

  ELOOP  欲打開的文件有過多符號連接問題,上限爲16符號連接

  EFAULT 參數buf爲無效指針,指向無法存在的內存空間

  EACCESS 存取文件時被拒絕

  ENOMEM 核心內存不足

  ENAMETOOLONG  參數file_name的路徑名稱太長

  範  例

  #include<sys/stat.h>

  #include<unistd.h>

  main()

  {

    struct stat buf;

    stat ("/etc/passwd",&buf);

    printf("/etc/passwd file size = %d\n",buf.st_size);

  }

  

  5.24  symlink   建立文件符號連接

  頭文 件

  #include<unistd.h>

  定  義

  int symlink( const char * oldpath,const char *newpath);

  函數說明

  symlink()以參數newpath指定的名稱來建立一個新的連接(符號連接)到參數oldpath所指定的已存在文件。參數oldpath指定的文件不一定要存在,如果參數newpath指定的名稱爲一已存在的文件則不會建立連接。

  函數說明

  成功則返回0,失敗返回-1,錯誤原因存於errno。

  錯誤代碼

  EPERM  參數oldpath與newpath所指的文件系統不支持符號連接

  EROFS  欲測試寫入權限的文件存在於只讀文件系統內

  EFAULT 參數oldpath或newpath指針超出可存取內存空間。

  ENAMETOOLONG  參數oldpath或newpath太長

  ENOMEM 核心內存不足

  EEXIST 參數newpath所指的文件名已存在。

  EMLINK 參數oldpath所指的文件已達到最大連接數目

  ELOOP  參數pathname有過多符號連接問題

  ENOSPC 文件系統的剩餘空間不足

  EIO   I/O存取錯誤

  範  例

  #include<unistd.h>

  main()

  {

    symlink("/etc/passwd","pass");

  }

  

  5.25  telldir   取得目錄流的讀取位置

  頭文 件

  #include<dirent.h>

  定  義

  off_t telldir(DIR *dir);

  函數說明

  telldir()返回參數dir目錄流目前的讀取位置。此返回值代表距離目錄文件開頭的偏移量返回值返回下個讀取位置,有錯誤發生時返回-1。

  錯誤代碼

  EBADF  參數dir爲無效的目錄流。

  範  例

  #include<sys/types.h>

  #include<dirent.h>

  #include<unistd.h>

  main()

  {

    DIR *dir;

    struct dirent *ptr;

    int offset;

    dir = opendir("/etc/rc.d");

    while((ptr = readdir(dir))!=NULL)

    {

      offset = telldir (dir);

      printf("d_name : %s offset :%d\n",ptr->d_name,offset);

    }

    closedir(dir);

  }

  

  5.26  truncate  改變文件大小

  頭文 件

  #include<unistd.h>

  定  義

  int truncate(const char * path,off_t length);

  函數說明

  truncate()會將參數path 指定的文件大小改爲參數length 指定的大小。如果原來的文件大?炔問齦ength大,則超過的部分會被刪去。

  函數說明

  執行成功則返回0,失敗返回-1,錯誤原因存於errno。

  錯誤代碼

  EACCESS 參數path所指定的文件無法存取。

  EROFS  欲寫入的文件存在於只讀文件系統內

  EFAULT 參數path指針超出可存取內存空間

  EINVAL 參數path包含不合法字符

  ENAMETOOLONG 參數path太長

  ENOTDIR   參數path路徑並非一目錄

  EISDIR 參數path 指向一目錄

  ETXTBUSY參數path所指的文件爲共享程序,而且正被執行中

  ELOOP  參數path’有過多符號連接問題

  EIO   I/O存取錯誤。

  

  5.27  umask  設置建立新文件時的權限遮罩

  頭文 件

  #include<sys/types.h>

  #include<sys/stat.h>

  定  義

  mode_t umask(mode_t mask);

  函數說明

  umask()會將系統umask值設成參數mask&0777後的值,然後將先前的umask值返回。在使用open()建立新文件時,該參數mode並非真正建立文件的權限,而是(mode&~umask)的權限值。例如,在建立文件時指定文件權限爲0666,通常umask值默認爲022,則該文件的真正權限則爲0666&~022=0644,也就是rw-r--r--返回值此調用不會有錯誤值返回。

  函數說明

  原先系統的umask值。

  

  5.28  unlink 刪除文件

  頭文 件

  #include<unistd.h>

  定  義

  int unlink(const char * pathname);

  函數說明

  unlink()會刪除參數pathname指定的文件。如果該文件名爲最後連接點,但有其他進程打開了此文件,則在所有關於此文件的文件描述詞皆關閉後纔會刪除。如果參數pathname爲一符號連接,則此連接會被刪除。

  函數說明

  成功則返回0,失敗返回-1,錯誤原因存於errno

  錯誤代碼

  EROFS  文件存在於只讀文件系統內

  EFAULT 參數pathname指針超出可存取內存空間

  ENAMETOOLONG 參數pathname太長

  ENOMEM 核心內存不足

  ELOOP  參數pathname 有過多符號連接問題

  EIO   I/O存取錯誤

  

  5.29  utime  修改文件的存取時間和更改時間

  頭文 件

  #include<sys/types.h>

  #include<utime.h>

  定  義

  int utime(const char * filename,struct utimbuf * buf);

  函數說明

  utime()用來修改參數filename文件所屬的inode存取時間。

  結構定義

  struct utimbuf

  {

    time_t actime;

    time_t modtime;

  };

  函數說明

  如果參數buf爲空指針(NULL),則該文件的存取時間和更改時間全部會設爲目前時間。執行成功則返回0,失敗返回-1,錯誤代碼存於errno。

  錯誤代碼

  EACCESS 存取文件時被拒絕,權限不足

  ENOENT 指定的文件不存在。

  

  5.30  utimes 修改文件的存取時間和更改時間

  頭文 件

  #include<sys/types.h>

  #include<utime.h>

  定  義

  int utimes(char * filename.struct timeval *tvp);

  函數說明

  utimes()用來修改參數filename文件所屬的inode存取時間和修改時間。

  結構定義

  struct timeval

  {

    long tv_sec;

    long tv_usec; /* 微妙*/

  };

  函數說明

  參數tvp 指向兩個timeval 結構空間,和utime()使用的utimebuf結構比較,tvp[0].tc_sec 則爲utimbuf.actime,tvp]1].tv_sec爲utimbuf.modtime。執行成功則返回0。失敗返回-1,錯誤代碼存於errno。

  錯誤代碼

  EACCESS 存取文件時被拒絕,權限不足

  ENOENT 指定的文件不存在

 

 

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