Unix环境高级编程---文件I/O

学习了一段时间Unix环境编程了,看到进程和线程这部分感觉之后,就感觉进步比较缓慢,所以在缓慢的过程中,希望可以多前面的知识进行一定的复习和巩固,希望以写的方式,加深对前面知识的理解。从第三章到第五章都是和文件和I/O相关的。这章总结的是第三章的相关内容。

  • 文件描述符

在Unix系统中,或者对于更加属性的Linux系统中,所有的设备都是用文件来统一定义的。文件描述符就是对文件的一种标识,所有的打开文件都通过文件描述符引用。文件描述符是一个非负整数。所有对文件的操作,比如读写,都可以通过文件描述符来对文件实施操作。

在Unix系统中,或者对于大多数操作系统中,定义了三个常用的文件描述符。

  • 文件描述符0与标准输入相关联
  • 文件描述符1与标准输出相关联
  • 文件描述符2与标准错误相关联
  • 在<unistd.h>中,将0,1,2定义了更具有可读性之的符号常量,STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO

  • 文件的打开,创建以及关闭

文件的打开、创建和关闭有以下函数原型

#include<fcntl.h>
int open(const char *path, int oflags, mode_t mode)
int openat(int fd, const char *path,int oflags, mode_t mode)

文件的打开、创建是在头文件fcntl.h中定义的。其中对open函数而言参数的含义是:

  • 第一个参数为路径名
  • 第二个参数为文件状态标志

O_RDONLY或0:可读

O_WRONLY或1:可写

O_RDWR或2:可执行

O_APPEND:每次写时都加到文件的尾部

O_CREAT:若此文件不存在则创建它,使用此选项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位

O_EXCL:如果同时指定了O_CREAT,而文件已经存在,则出错,这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作

O_TRUNC:如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0

O_NOCTTY:如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端

O_NONBLOCK:如果pathname指的是一个FIFO,一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式

O_SYNC:使每次write都等到物理I/O操作完成


  • 第三个参数一般为文件权限,第三个参数一般在创建新文件才会使用这个参数。即第二个参数选择为O_CREAT

S_IRWXU,0700:代表该文件所有者具有可读,可写,可指向的权限

S_IRUSR或S_IREAD,0400:代表该文件所有者具有可读取的权限

S_IWUSR或S_IWRITE,0200:代表该文件所有者具有可写入的权限

S_IXUSR或S_IEXEC,0100:代表该文件所有者具有可指向的权限

S_IRWXG,0070:代表该文件用户组具有可读,可写,可执行的权限

S_IRGRP,0040:代表该文件用户组具有可读的权限

S_IWGRP,0020:代表该文件用户组具有可写的权限

S_IXGRP,0010:代表该文件用户组具有可执行的权限

S_IRWXO,0007:代表其他用户具有可读,可写,可执行的权限

S_IROTH,0004:代表其他用户具有可读的权限

S_IWOTH,0002:代表其他用户具有可写的权限

S_IXOTH,0001:代表其他用户具有可执行的权限

open函数和openat函数的区别在于:

  • path函数指定的是绝对路径名的时候,fd参数可以被忽略,openat函数相当于open函数
  • path函数指定的是相对路径名的时候,fd参数指出了相对路径名在文件系统中的开始地址,fd参数是通过打开相对路径名所在目录来获取。
  • path参数指定了相对路径名,fd参数具有特殊值AT_FDWD,这种情况下,路径名在当前目录中获取,这个时候两个函数功能类似。

看到这里的时候,个人本能的是蒙蔽的,主要是书上没有给出具体的例子,加上还没有接触第四章内容于是乎就去查阅了相关的资料。比如对于一个文件,其绝对路径名是home/effort/桌面/apue.3e/fileio/output.log。其目录路径为home/effort/桌面/apue.3e,那么fd指的就是目录的路径,path指代的就是output.log,简单的使用如下:

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

int main()
{
  DIR *dir;
  int dirfd2;
  int fd;
  int n;

  dir = opendir("../fileio");
  if(NULL == dir)
  {
    perror("open dir error");
    return -1;
  }
  dirfd2 = dirfd(dir);
  if(-1 == dirfd2)
  {
    perror("dirfd error");
    return -1;
  }

  fd = openat(dirfd2,"output.log",O_CREAT|O_RDWR|O_TRUNC);
  if(-1 == fd)
  {
    perror("opeat error");
    return -1;
  }
  n = write(fd,"Hello world!\n",15);
  
  close(fd);
  closedir(dir);

  return 0;

}

运行程序之前,文件内容如下:


运行之后:


  • 文件的关闭

文件的关闭的函数是在头文件unistd.h(很想知道,问啥不在一个统一的头文件里面),函数原型为:

#include<unistd.h>
int close(fd)
当一个进程终止时,内核会自动关闭它所有打开的文件,很多时候都会利用这种功能而不显式地调用close关闭文件

  • 文件的读写和定位

当打开文件后,拥有对文件的读写的权限时,我们就可以对于文件进行读写了。很多时候,我们还面临着在文件不同的位置进行操作的需求,因此还需要对文件进行定位操作。文件的定位意思是将使文件读写从当前文件偏移量处开始。一般打开文件时,默认的情况下为0。

所谓的当前文件偏移量是用于度量从该文件开始处计算的字节数。可以调用lseek显式地打开一个文件设置偏移量。函数原型为:

#include<unistd.h>
off_t lseek(int fd, off_t offset, int wherence)
其中offset和第三个参数wherence紧密相关,具体关系如下:

wherenceSEEK_SET,则文件偏移量设置为距当前文件开始处offset个字节

wherenceSEEK_CUR,则文件偏移量设置为距当前值加上offset,offset可负可正

wherenceSEEK_END,则文件偏移量设置为文件长度加offset,同样可负可正

若lseek调用成功,则返回新的文件偏移量。

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

int main()
{
    int fd;
    fd=open("./output.log",O_RDONLY);
    if(fd<0)
    {printf("can not open file");return -1;}

  off_t offset;
  offset=lseek(fd,0,SEEK_CUR);
  printf("%d\n",offset);

  offset=lseek(fd,0,SEEK_END);
  printf("%d\n",offset);
}

其中output.log的内容为:hello

输出结果为:



从文件中读取数据,需要调用read函数,read函数模型为:

#include<unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes)
若read成功,则返回读到的字节数,如已到达文件末尾,则返回0. 读操作从当前偏移量开始,在成功返回之前,该偏移量将会增加实际读到的字节数。

向文件中写数据这需要write函数。

#include<unistd.h>
ssize_t write(int fd, const void* buf, size_t nbytes)
若写成功,则返回实际写入的字节数,否则返回-1.所以一般判定写数据成功,不能单单只从-1来判断,而应该从返回实际的写入字节数和nbytes比较,相等则表示写入数据成功。

对于读写数据而言,都是从当前文件偏移量开始的,所以要锁定任意位置,lseek就可以发挥作用了。

此外还有一个问题,就是对于buf大小的选定。在APUE第三章对此内容进行了详细的解释:文件系统为ext4的磁盘长度为4096字节。经过测试,系统CPU时间最小为4096左右及以后的位置,因此很多时候,我们都看点BUFFSIZE为4096的原因了。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值