第三章 文件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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值