第三章 文件I/O

函數open和openat

打開或新建一個文件

  #include <fcntl.h>

  int open(const char *path,int oflag...../*mode_t mode*/);

  int openat(int fd,const char *path,int oflag.../*mode_t mode*/);

              函數的返回值:若成功,返回文件描述符;若出錯,返回-1;
我們將最後一個參數寫爲….,這種方法表明餘下的參數的數量和類型是可變的。
   
path參數是要打開或創建文件的名字。oflag參數可用來說明此函數的多個選項(只讀,只寫,讀寫);

  1. 當path參數是絕對路徑,兩個函數一致
  2. 當path是相對路徑,fd參數指出了相對路徑名在文件系統的開始地址,
  3. path是相對參數,fd參數具有特殊值AT_FDCWD,這種情況下,路徑名在當前工作目錄獲取,這個時候openat和open功能類似。

open和openat函數返回的文件描述符一定是最小的未用描述符值。

函數creat

創建一個新文件

  #include<fcntl.h>

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

          返回值:若成功,返回爲只寫打開的文件描述符;若出錯,返回-1;

等效open(path,O_WRONLY|O_CREAT|O_TRUNC,mode);

函數close

  #include<unistd.h>

  int close(int fd);

    返回值:若成功,返回0;若出錯,返回-1;

函數lseek

調用lseek 顯式地爲一個打開的文件設置偏移量

 #include<unistd.h>

  off_t lseek(int fd,off_t offset,int whence);

      返回值:若成功,返回新的文件偏移量;若出錯,返回-1;
參數offset與whence有關:

  1. 若whence 是SEEK_SET,偏移量爲文件開始處offset
  2. 若whence是SEEK_CUR,偏移量爲當前值加offset,offset可正可負;
  3. 若whence是SEEK_END,偏移量設置爲文件長度加offset,可正可負

如下,當文件偏移量大於文件長度時,系統是如何保存文件的

#include<apue.h>
  2 #include<fcntl.h>
  3 
  4 char buf1[]="abcdefghij";
  5 char buf2[]="ABCDEFGHIJ";
  6 
  7 int main()
  8 {
  9     int fd;
 10     if((fd=creat("file.hole",FILE_MODE))<0)
 11         err_sys("create error");
 12     if(write(fd,buf1,10)!=10)
 13         err_sys("buf1 write error");
 14     //offset now=10
 15     if(lseek(fd,16384,SEEK_SET)==-1)
 16         err_sys("lseek error");
 17     //offset now=16384
 18 
 19     if(write(fd,buf2,10)!=10)
 20         err_sys("write buf2 error");
 21     //offset now=16394
 22     exit(0);
 23 }

file_hole.c
函數read

從打開的文件中讀數據

 #include<unistd.h>

  ssize_t read(int fd,void* buf,size_t nbytes);

      返回值:讀到的字節數,若已到文件尾,返回0;若出錯:返回-1;

函數write

向打開文件寫數據

 #include<unistd.h>

  ssize_t write(int fd,const void*buf,size_t nbytes);

      返回值:若成功,返回已經寫的字節數;若出錯,返回-1;
其返回值通常與nbytes的值相同,否則出錯;
  

1 #include<apue.h>
  2 
  3 #define BUFFSIZE 4096
  4 
  5 int main()
  6 {   
  7     int n;
  8     char buf[BUFFSIZE];
  9     while((n=read(STDIN_FILENO,buf,BUFFSIZE))>0)
 10         if(write(STDOUT_FILENO,buf,n)!=n)
 11             err_sys("write error");
 12     if(n<0)
 13         err_sys("read error");
 14     exit(0);
 15 }          

Read_Write.c

文件共享

文件的三種結構
1.記錄項:包含一張打開文件描述符表
2.文件表
3.V節點:包含了文件類型和操作文件的各種函數的指針

原子操作

函數pread和pwrite

#include<unistd.h>
ssize_t pread(int fd,void *buf,size_t nbytes,off_t offset);
//返回值:讀到的字節數,若已到文件尾,返回0,若出錯,返回-1
ssize_t  pwrite(int fd,const void *buf,size_t nbytes,off_t offset);
//返回值:若成功,返回已寫的字節數;若出錯,返回值-1

調用pread 相當於調用lseek後調用read,但是pread又與這種順序調用有下列重要區別:

  • 調用pread時,無法中斷其定位和讀操作
  • 不更新當前文件偏移量
函數dup和dup2
兩個函數都可以複製一個現有的文件描述符
#include<unistd.h>
int dup(int fd);
int dup2(int fd,int fd2);
//兩函數的返回值:若成功,返回新的文件描述符;若出錯,返回-1
由dup返回的文件描述符一定是當前可用描述符中最小的值。對dup2,可以用fd2參數指定新描述符的值。如果fd2已經打開,則先將其關閉,若fd等於fd2,則dup2返回fd2,而不關閉它。
函數sysnc、fsync和fdatasync
將緩衝區的數據寫入磁盤
#include<unistd.h>
int fsync(int fd);
int fdatasync(int fd);
//返回值:若成功,返回0;若出錯,返回-1;
void sync(void);
sync只是將所有修改過的塊緩衝區排入寫隊列,不等其是否寫完就返回。
fsync支隊fd指定的文件起作用並且等待寫完才返回結束。
fdatasync類似fsync,但fsync隻影響文件的數據部分,而除數據外,fdatasync還會同步更新文件的屬性
函數fcntl
可以改變已經打開的文件的屬性
#include<fcntl.h>
int fcntl(int fd,int cmd,.../*int arg */);
//返回值:若成功,則依賴於cmd;若出錯,返回-1;

fcntl函數有以下5中功能

(1) 複製一個已有的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)
(2)獲取/設子文件的描述符標誌(cmd=F_GETFP或F_SETFD)
(3)獲取/設置文件狀態標誌(cmd=F_GETFL或F_SETFL)
(4)獲取/設置異步I/O所有權(cmd=F_GETOWN或F+SETOWN)
(5)獲取/設置記錄鎖(cmd=F_GETLK、F_SETLK或F_SETLKW)
程序的第一個參數指定文件描述符,並對還描述符打印其所選擇的文件標誌說明

#include<apue.h>
#include<fcntl.h>

   int main(int argc,char* argv[])
   {   
       int val;

       if(argc!=2)
           err_sys("usage:DupTest<descriptor#>");
      if((val=fcntl(atoi(argv[1]),F_GETFL,0))<0)
              err_sys("fcntl error for fd %d",atoi(argv[1]));

      switch(val&O_ACCMODE){
          case O_RDONLY:
              printf("read only");
              break;
          case O_WRONLY:
              printf("write only");
              break;
          case O_RDWR:
              printf("read write");
              break;
          default:
              printf("unkown access mode");
      }

      if(val&O_APPEND)
          printf(", append");
      if(val&O_NONBLOCK)
          printf(", nonblock");
      if(val&O_SYNC)
          printf(", synchronous writes");

  #if !defined(_POSIX_C_SOURCE)&&defined(O_FSYNC)&&(O_FSYNC!=O_SYNC)
      if(val&O_FSYNC)
          printf(", synchronous writes");
  #endif
      putchar('\n');
      exit(0);
  }

/dev/fd
較新的系統都提供名爲/dev/fd/的目錄,其目錄項時名爲0、1、2等的文件。打開文件/dev/fd/n等效於複製描述符n。某些系統提供路徑名/dev/stdin,/dev/stdout和/dev/stderr,這些等效於/dev/fd/0,/dev/fd/1和/dev/fd/2

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