底层文件的访问

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YL970302/article/details/83782798

一、write系统调用

头文件:<unistd.h>

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

系统调用write的作用是:把缓冲区buff的前nbytes个字节写入与文件描述符fd关联的文件中,它返回实际写入的字节数。如果文件描述符有错或者底层的设备驱动程序对数据块长度比较敏感,该返回值可能会小于nbytes。如果这个函数返回0,就表示未写入任何数据;如果它返回的是-1.就表示在write调用中出现了错误,错误代码保存在全局变量errno里。

二、read系统调用

头文件:<unistd.h>

size_t read(int fd, void *buff, size_t nbytes);

系统调用read的作用是:从与文件描述符fd关联的文件里读入nbytes个字节的数据,并把它们放到buff缓冲区中,它返回实际读入的字节数,这可能会小于请求的字节数。如果read调用返回0,就表示未读入到任何数据,已到达文件尾。同样,如果返回的是-1,就表示read调用出现了错误。

下面给出一段代码:

 #include<unistd.h>
 #include<stdlib.h>
 
 int main()
 {
     char buffer[128];
     int nread;
 
     nread = read(0,buffer,128);
     if( nread == -1 )
     {
         write(2,"A read error has occurred\n",26);
     }
 
     if((write(1,buffer,nread)) != nread)
     {
         write(2,"A write error has occurred\n",27);
     }
     exit(0);
 }

运行有下面三种方式:

(1)直接运行然后输入

(2)使用echo通过管道为程序提供输入(注:echo会将输入的字符串送往标准输出。输出的字符串间以空白字符隔开,并在最后加上换行号)

(3)创建一个文件,然后通过文件重定向输入

三、open系统调用

为了创建一个新的文件描述符,需要使用系统调用open

头文件:<fcntl.h>、<sys/types.h>、<sys/stat.h>

int open ( const char *path, int oflags);

int open (const char *path, int oflags, mode_t mode );

  • path:准备打开的文件或设备的名字
  • oflags:用于指定打开文件所采取的动作,它是通过必需文件访问模式与其他可选模式相结合的方式来指定的,open调用必须指定下面的文件访问模式之一
  • 模式 说明
    O_RDONLY 以只读方式打开
    O_WRONLY 以只写方式打开
    O_RDWR 以读写方式打开

    open调用还可以在oflags参数中包括下列可选模式的组合(用“按位或”操作)

  • O_APPEND:把写入数据追加在文件的末尾
  • O_TRUNC:把文件长度设置为零,丢弃已有的内容
  • O_CREAT:如果需要,就按参数mode中给出的访问模式创建文件
  • O_EXCL:与O_CREAT一起使用,确保调用者创建出文件。open调用是一个原子操作,也就是说,它只执行一个函数调用。使用这个可选模式可以房子和两个程序同时创建同一个文件,如果文件已存在,open调用失败

       简单的讲,open建立了一条到文件或设备的访问路径,如果调用成功,它将返回一个可以被read、write和其他系统调用使用的文件描述符。这个文件描述符是唯一的,它不会与任何其他运行中的进程共享。如果两个程序同时打开同一个文件,它们会分别得到两个不同放入文件描述符,如果它们都对文件进行写操作,那么它们会各写各的,它们会分别接着上次离开的位置继续往下写。它们的数据不会交织在一起,而是彼此互相覆盖。两个程序对文件的读写位置(偏移值)不同,所以你可以通过使用文件锁功能来防止出现冲突。

      open调用在成功时返回一个新的文件描述符(总是一个非负整数),在失败时返回-1并设置全局变量errno来指明失败的原因,新文件描述符总是使用未用描述符的最小值,例如:如果一个程序关闭了它的标准输出,然后再次调用open,文件描述符1就会被重新使用,并且标准输出将被有效地重定向到另一个文件或设备。

下面我们结合上面的几个函数写一段简单的代码

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<fcntl.h>
  5 #include<assert.h>
  6 #include<stdlib.h>
  7 
  8 int main()
  9 {
 10 
 11     char buff[256] = {0};
 12     int fdr = open("passwd",O_RDONLY);
 13     assert(fdr != -1);
 14 
 15     int fdw = open("newpasswd",O_WRONLY|O_CREAT,0600);
 16     assert(fdw != -1);
 17 
 18     int n = 0;
 19 
 20     while( (n = read(fdr,buff,256)) > 0)
 21     {
 22         write(fdw,buff,n);
 23     }
 24 
 25     close(fdr);
 26     close(fdw);
 27 
 28     exit(0);
 29 }

注:每次产生新的描述符之后一定要进行断言,使用完描述符之后一定要记得关闭

四、访问权限的初始值

1、当使用带有O_CREAT标志的open调用来创建文件时,必须使用有3个参数格式的open调用,第三个参数mode是几个标志按位或后得到的,这些标志在头文件sys/stat.h中定义。

2、有几个因素会对 文件的访问权限产生影响

  • 指定的访问权限只有在创建文件时才会使用
  • 用户掩码(由shell的umask命令设定)会影响到被创建文件的访问权限,open调用里给出的mode值将与当时用户掩码的反值做AND操作
  • 举例:如果用户掩码被设置为001,并且指定了S_IXOTH(执行权限,其他用户)模式标志,那么其他用户对创建的文件不会拥有执行权限,因为用户掩码中指定了不允许向其他用户提供执行权限,因此open和creat调用中的标志实际上时发出设置文件访问权限的请求,所请求的权限是否会被设置取决于当时的umask的值

3、umask:当我们登陆系统之后创建一个文件总是有一个默认权限的,那么这个权限是怎么来的呢?这就是umask干的事情,umask设置了用户创建文件的默认权限,它与chmod的效果刚好相反,umask设置的是权限的“补码”,而chmod设置的是文件权限码。

  • 一般格式: umask[选项][掩码],该命令用来设置权限新文件的掩码(一般讲,umask命令是在/etc/profile文件中设置的)。当新文件被创建时,其最初的权限由文件创建掩码决定。用户每次注册进入系统时,umask命令都被执行,并且自动设置掩码改变默认值,新的权限将会把旧的覆盖
  • 选项及其含义:-S:显示当前的掩码,umask是从权限中”拿走“相应的位,且文件创建时不能赋予执行权限
  • umask命令允许你设定文件创建时的缺省模式,对应每一类用户(文件属主、同组用户、其他用户)存在一个相应的umask值中的数字,对于文件来说,这一数字的最大值为6,系统不允许你在创建一个文本文件时就赋予它执行权限,必须在创建后用chmod命令增加这一权限,目录则允许设置执行权限,这样针对目录来说,umask中各个数字最大可以到7.
  • 该命令形式:umask nnn,其中nnn为umask值 000-777

五、close系统调用

   可以使用close调用终止文件描述符fildes与其对应文件之间的关联。文件描述符被释放并能够重新使用,close调用成功时返回0,出错时返回-1

  • 头文件:<unistd.h>
  • int close(int fildes)
  • 注意:检查close调用的返回结果非常重要,有的文件系统,特别时网络文件系统,可能不会在关闭文件之前报告写操作中出现的错误,这是因为在执行写操作时,数据可能未被确认写入。

六、ioctl系统调用

    ioctl调用有点像是个大杂烩,它提供了一个用于控制设备及其描述符行为和配置底层服务的接口,终端、文件描述符、套接字甚至磁带机都可以有为它们定义的ioctl。

猜你喜欢

转载自blog.csdn.net/YL970302/article/details/83782798