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

本文详细介绍了Unix系统中文件描述符的概念及其应用,包括标准输入输出、文件的打开与关闭方法、文件读写及定位操作等内容,并通过示例程序演示了相关函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习了一段时间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的原因了。



本书全面介绍了UNIX系统的程序设计界面—系统调用界面和标准C库提供的许多函数。 本书的前15章着重于理论知识的阐述,主要内容包括UNIX文件和目录、进程环境、进程控制、 进程间通信以及各种I/O。在此基础上,分别按章介绍了多个应用实例,包括如何创建数据库函数库, PostScript 打印机驱动程序,调制解调器拨号器及在伪终端上运行其他程序的程序等。 本书内容丰富权威, 概念清晰精辟,一直以来被誉为UNIX编程的“圣经”,对于所有UNIX程序员—无论是初学者还是专家级人士 —都是一本无价的参考书籍。 目 录 译者序 译者简介 前言 第1章 UNIX基础知识 1 1.1 引言 1 1.2 登录 1 1.2.1 登录名 1 1.2.2 shell 1 1.3 文件和目录 2 1.3.1 文件系统 2 1.3.2 文件名 2 1.3.3 路径名 2 1.3.4 工作目录 4 1.3.5 起始目录 4 1.4 输入和输出 5 1.4.1 文件描述符 5 1.4.2 标准输入、标准输出和标准 出错 5 1.4.3 不用缓存的I/O 5 1.4.4 标准I/O 6 1.5 程序和进程 7 1.5.1 程序 7 1.5.2 进程和进程ID 7 1.5.3 进程控制 7 1.6 ANSI C 9 1.6.1 函数原型 9 1.6.2 类属指针 9 1.6.3 原始系统数据类型 10 1.7 出错处理 10 1.8 用户标识 11 1.8.1 用户ID 11 1.8.2 组ID 12 1.8.3 添加组ID 12 1.9 信号 12 1.10 UNIX时间值 14 1.11 系统调用和库函数 14 1.12 小结 16 习题 16 第2章 UNIX标准化及实现 17 2.1 引言 17 2.2 UNIX标准化 17 2.2.1 ANSI C 17 2.2.2 IEEE POSIX 18 2.2.3 X/Open XPG3 19 2.2.4 FIPS 19 2.3 UNIX实现 19 2.3.1 SVR4 20 2.3.2 4.3+BSD 20 2.4 标准和实现的关系 21 2.5 限制 21 2.5.1 ANSI C限制 22 2.5.2 POSIX限制 22 2.5.3 XPG3限制 24 2.5.4 sysconf、pathconf 和fpathconf 函数 24 2.5.5 FIPS 151-1要求 28 2.5.6 限制总结 28 2.5.7 未确定的运行时间限制 29 2.6 功能测试宏 32 2.7 基本系统数据类型 32 2.8 标准之间的冲突 33 2.9 小结 34 习题 34 第3章 文件I/O 35 3.1 引言 35 3.2 文件描述符 35 3.3 open函数 35 3.4 creat函数 37 3.5 close函数 37 3.6 lseek函数 38 3.7 read函数 40 3.8 write函数 41 3.9 I/O的效率 41 3.10 文件共享 42 3.11 原子操作 45 3.11.1 添加至一个文件 45 3.11.2 创建一个文件 45 3.12 dup和dup2函数 46 3.13 fcntl函数 47 3.14 ioctl函数 50 3.15 /dev/fd 51 3.16 小结 52 习题 52 第4章 文件和目录 54 4.1 引言 54 4.2 stat, fstat和lstat函数 54 4.3 文件类型 55 4.4 设置-用户-ID和设置--ID 57 4.5 文件存取许可权 58 4.6 新文件和目录的所有权 60 4.7 access函数 60 4.8 umask函数 62 4.9 chmod和fchmod函数 63 4.10 粘住位 65 4.11 chown, fchown和 lchown函数 66 4.12 文件长度 67 4.13 文件截短 68 4.14 文件系统 69 4.15 link, unlink, remove和rename 函数 71 4.16 符号连接 73 4.17 symlink 和readlink函数 76 4.18 文件的时间 76 4.19 utime函数 78 4.20 mkdir和rmdir函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值