APUE文件io

第三章 文件i/o

3.1引言

  • 不带缓冲的io(unix系统在内核中设有缓冲区,这个不带缓冲意思是用户不自己缓冲)
    • 每个read和write都调用内核中的一个系统调用

3.2 文件描述符

  • 对于内核而言,所有打开的文件都通过文件描述符引用,是一个非负整数。打开或创建一个文件的时候,内核返回一个文件描述符。
  • UNIx系统shell把文件描述符0与进程的标准输入关联,文件描述符1与标准输出关联,文件描述符与标准错误关联。

3.3函数open和openat

  • 调用这个两个函数可以打开一个文件
    #include 
    
    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参数可以使用下面的常量进行或运算构成oflag参数

    • O_RDONLY //只读打开 0
    • O_WRONLY //只写打开 1
    • O_RDWR //读写打开 2
    • O_EXEC //只执行打开
    • O_SEARCH //只搜索打开
    • O_APPEND //写时追加
    • O_CLOEXEC //把FD_CLOEXEC 常量设置为文件描述符的标志
    • O_CREAT //若此文件不存在则创建它
    • O_DIRECTORY //如果path引用的不是目录,则出错
    • O_EXCL //如果同时制定了O_CREAT,而文件已经存在,则出错,可以用此测试文件是否存在
    • O_NOCTTY //如果path引用的时终端设备,则不将该设备分配作为此进程的控制终端
    • O_NOFOLLOW //如果path引用的时一个符号链接,则出错
    • O_NONBLOCK //如果path引用的是一个FIFO,块设备或字符文件,则设置为非阻塞i/o
    • O_SYNC //每次write都等待物理i/o操作完成
    • O_TRUNC //如果文件存在,而且为制度或读写成功打开,则将其长度截断为0
    • O_TTY_INIT //如果打开一个还未打开的终端设备,设置非标准termios的参数值,使其符合sus
    • O_DSYNC //使每次write都要等待物理i/o操作完成
    • O_RSYNC // 使每一个以文件描述符作为参数进行的read操作等待,直至所有对文件同一部分挂起的写操作完成
  • 由open和openat返回的文件描述符一定是最小的未用文件描述符数值。

  • fd参数把open和openat参数区分开,共有三种可能性

    • path时绝对路径名,这种情况忽略fd参数,openat相当于openat
    • path参数指定的时相对路径名,fd参数指出相对路劲名的开始地址,fd参数是通过打开相对路径名所在的目录来获取的
    • path参数制定了相对路径名,fd参数具有特殊值AT_FDCWD,这种情况下,路径名在当前工作目录中获取,openat函数在操作上与open函数一致
  • openat()是在新增的一类函数之一希望解决两个问题:

    • 让线程可以使用相对路径名打开目录中的文件,而不再只能打开当前工作目录
    • 可以避免time-of-check-to-time-of-use(TOCTTOU) 错误
  • 文件名和路径名截断

    • 如何找到一个系统的NAME_MAX
      • 使用sysconf函数和pathconf,fpathconf函数,通过传递name参数来获得系统的各个限制值
    • 如果NAME_MAX是14,我们试图再当前目录中创建一个文件名15的新文件,则会发生什么?
      • 不同系统对该种情况有不同的反应

3.4 函数creat

#include 
int create(const char *path, mode_t mode) ;
    //返回值;若成功,返回为只写打开的fd,出错-1
    //这个函数等效于
    open(path,O_WRONLY|O_CREAT|O_TRUNC,mode) ;
  • creat函数的不足之处时它以只写的方式打开所创建的文件

3.5 函数close

#include 
int close(int fd) ;
  • 关闭一个文件还会释放该进程加载该文件上的所有记录锁

3.6 函数lseek

  • 每个打开文件都有一个与其相关的当前文件偏移量(current file offset),用以度量从文件开始处计算的字节数。
  • 通常读写操作都是从当前文件偏移量开始,并使偏移量增加所读写的字节数
  • 系统默认的情况,打开一个文件时,除非指定O_APPEND选项,否则偏移量设为0
  • 可以显示的调用lseek为打开的文件设置偏移量
#include 
off_t lseek(int fd, off_t offset, int whence);
    //成功返回新的偏移量,出错返回-1
  • 对于参数offset的值的解释和whence的值有关
    • 如果whence时SEEK_SET,则该文件的偏移量设置为据文件开始处offset字节
    • 如果whence时SEEK_CUR,则该文件的偏移量设置为当前值加offset,offset可正可负
    • 如果whence时SEEK_END,则该文件的偏移量设置为据文件长度加offset字节,offset可正可负
  • 若lseek成功执行,则返回新的文件偏移量,为此可用下列的方式打开文件偏移量
off_t currpos ;
currops = lseek(fd, 0, SEEK_CUR) ;

上面的方法也可以用来判断涉及的文件是否可以设置偏移量

  • lseek仅当当前文件偏移量记录都在内核中,并不引起I/O操作,然后偏移量被用于下一个读写操作
  • 文件偏移量可以大于文件长度,对该文件的下一次写将加长该文件并形成一个空洞,位于文件中但是没有写过的字节都被读为0
  • 文件空洞不要求在磁盘上占用存储区,具体处理方式和文件系统有关
  • 因为lseek使用的偏移量是用offset表示的,所以允许具体实现根据各自特定平台自行选择大小合适的数据类型。

3.7 函数read

#include 
ssize_t read(int fd, void *buf, size_t nbytes) ;        //void * 表示通用指针
    //返回:读到的字节数,若已到文件尾,返回0,出错返回-1
  • 有多种情况可以使读到的字节数少于要求读的字节数
    • 读普通文件时,读到文件要求的字节数前已经到达文件尾端
    • 当从终端设备读时,通常一次最多读一行
    • 当从网络读时,网络中的缓冲区机制可能造成返回值小于要求读的字节数
    • 当从管道和FIFO读时,如果管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数
    • 当一信号中断,而已经读了的部分数据量时
  • 读操作从文件的当前偏移量处开始,在成功返回之前,该偏移量将增加时机读到的字节数

3.8 函数write

    #Include  
    
    ssize_t write(int fd, const void *buf, size_t nbytes) ;
    //成功返回已写的字节数,出错返回-1
  • 返回值通常和nbytes的值相同,否则意味着出错
  • write出错的常见原因是磁盘已经满了,或者超过了一个给定进程的文件长度限制
  • 对于普通文件,写操作从文件的当前偏移量开始,如果在打开该文件时制定了O_APPEND选项,则每次都将文件偏移量移到末尾
  • 一次成功写,offset增加实际写的字节数

3.9 I/O的效率

  • 当缓冲区长度为4096的时候,继续增加缓冲区长度对程序的用户cpu时间几乎没有影响了(应该和i/o的接口读取速率有关)
  • 大多数文件系统为了改善性能采取了预读技术
  • 预读就是当检测到正在顺序读的时候,系统就试图读取比应用所要求的更多的数据

3.10 文件共享

  • unxi系统支持在不同进程之间共享文件
  • 内核使用三种数据结构表示打开的文件
    • 每个进程在进程表项中都有一个记录项,记录项中包含一张打开的文件描述符表
    • 文件表项 :内核为所有打开的文件按维持一张文件表,每个表项包含如下几项
      • 当前文件状态标志(读,写,追加,。。。)
      • 当前文件偏移量
      • 指向该文件v-node表象的指针
    • 每个打开文件都有一个v-node结构(linux下的i-node),包含文件类型和对此文件进行各种操作的函数的指针
      • 大多数文件的v-node还包含该文件的i-node,这些信息时在打开文件的受从磁盘读入内存的
  • 如果一个文件被多个进程打开,打开该文件的每个进程都获得一个文件表项,并且每个进程有自己的文件偏移量

3.11 原子操作

  1. 追加到一个文件
  • 原子操作为了避免先对文件进行偏移量设置,但是该进程被内核换下,然后另外一个对该偏移量进行了重新设置,导致切到原先进程的时候出现偏移量的错误。会出现数据覆盖之类的情况
  • 使用O_APPEND,在每次写之前,都会将文件偏移量放到最后
  1. 函数pread和pwrite
  2. 创建一个文件
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset) ;
 #成功返回读到的字节数出错返回-1
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset) ;
 # 成功返回已写的字节数,出错返回-1
  • 原子操作指的是多步组成的一个操作,如果该操作执行,要么全部都执行完,要么一步都不执行,不能只执行其中的一步

3.12 函数dup和dup2

复制现有文件描述符

int dup(int fd) ; //返回新文件描述符时当前可用文件描述符中最小值
int dup2(int fd, int fd2) ; //fd2可以指定新描述符的值。

3.13 函数sysnc,fsync和fdatasysnc

  • 延迟写:当我们向文件写数据时,内核通常先将数据复制到缓冲区中,然后排入队列,晚些时候在写入磁盘
  • 通常,当内核需要重用缓冲区来存放其他磁盘块数据时候,它会把所有延迟写数据块写入磁
  • 为了保证磁盘上时机文件系统和缓冲区中内容的一致性,unix系统提供了以下三个函数
  • update系统守护进程周期性的调用sync函数,定期(大约30s)flush缓冲区。
#include 

int fsync(int fd) ; //只对由文件描述符fd指定的一个文件起作用,等待写磁盘结束后返回,一般用于数据库
int fdatasync(int fd) ; //类似于fsync,只影响文件的数据部分。

void sync(void) ;   //将所有修改过的块缓冲区排入写队列,然后返回,实际上并不等待写磁盘结束

3.14 函数fcntl

可以改变已经打开文件的属性

    int fcntl(int fd, int cmd, ...//int arg);
  • 第三个参数是指向一个结构的指针
  • fcntl函数有一下几个功能
    • 复制一个已有文件描述符(cmd=FDUPFD 或FDUPFD_CLOEXEC)
    • 获取/设置文件描述符标志(cmd=F_GETFD/FSETFD)
    • 获取/设置文件状态(cmd=GETFL/SETFL)
    • 获取/设置异步i/o所有权(cmd=F_GETOWN/SETOWN)
    • 获取设置记录锁(cmd=F_GETLK,F_SETLK/F_SETLKW)
      -每个cmd的意思
    • F_DUPFD
      • 复制文件描述符fd
    • F_DUPFD_CLOEXEC
      • 复制文件描述符,设置与新文件描述符关联的FD_CLOEXEC文件描述符值,返回新文件描述符
    • F_GETFD
      • 对于fd的文件描述符标志作为函数值返回
    • F_SETFD
      • 对于fd设置文件描述符标志
    • F_GETFD
      • 对应于fd的文件状态标志作为函数值返回。
    • F_SETFL
      • 将文件状态标志设置为第三个参数的值
    • F_GETOWN
      • 获取当前SIGIO和SIGURG信号的进程ID或进程组id。

3.16 /dev/fd

较新的系统都提供名为/dev/fd的目录,其目录项为0,1,2,等的链接文件,打开文件/devfd/n等效于复制描述符n

第四章 文件和目录

4.1 引言

文件系统的其他特征和文件的性质,属性

4.2 函数stat,fstat,fstatat和lstat

#include 

int stat(const char *restrict pathname, struct stat *restrict buf) ;
int fstat(int fd, struct stat *buf) ;
int lstat(const char * restrict pathname, struct stat * restrict buf) ;
int fstatat(int fd, const char *restarict pathname, stuct stat * restrict buf ,int flag)

这些stat用于返回文件有关的信息结构。

  • 同时stat也是一个结构体,用于保存文件的一些信息

4.3文件类型

  • 普通文件
  • 目录文件
    • 只有内核能写
  • 块设备文件
  • 字符设备文件
    • 提供对设备不带缓冲的访问
  • fifo
    • 用于ipc
  • socket
    • 用于进程网络间通信
  • 符号链接
    • 指向另一个文件
// 测试文件属性
#include 
#include "apue.h"
#include 
#include 

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

   int i ;
   struct  stat buf ;
   char *ptr ;
   for (i=1;i

4.4 设置用户id和设置组id

  • 每个文件有三类id
    • 实际用户id--------标志我们是谁(标记操作的用户)
    • 有效用户id--------标识用于文件访问权限检查
    • 设置用户id--------用于exec函数保存
  • 通常uid=有效用户id
  • st_mode(stat中的一项)中可以设置一个特殊标志,含义时当执行这个文件的时候,将进程的有效用户id者之谓文件所有者的用户id----set_ser_ID
  • 还可以将执行此文件的进程的有效组id设置为文件所有组的id -----set-groups-ID
  • 如果文件按所有者时超级用户权限,而且设置了该文件的设置用户id位,那么当该程序文件执行的时候,该进程具有root权限,不管执行该程序的时机用户id是多少

4.5 文件访问权限

  • 所有的文件类型都有权限
  • 权限有读写执行三种
  • 三种权限的使用方式如下
    • 当用名字打开任一类型文件时,对该名字中包含的每个目录,都应具有执行权限
      • 对目录的读权限,允许我们读目录,获得目录中的文件名列表(可以ls不能cd)
    • 对一个文件的读/写权限决定我们是否能够打开现有文件进行读/写操作
    • 在一个目录中创建文件,必须对该目录有执行和写权限
    • 为了删除现有文件,必须有 x w,对该文件本身不需要有x w
    • 如果用7各exec函数终端额任何一个执行文件,都必须对该文件具有执行权限
  • 进程每次操作文件会进行权限测试,测试一般使用有效用户id

4.6 新文件和目录的所有权

  • 新文件的用户id设置为进程的有效用户id
  • 关于组id
    • 可以时进程有效组id
    • 可以时所在目录的组id

4.7 函数access和faccessat

access和faccessat按照实际用户id和实际组id进行访问权限测试

#include
  • flag参数用于改变faccessat 的行为,如果flag设置为AT_EACCESS,访问检查用的时调用进程的有效用户id和有效组id

4.8 函数umask

  • umask函数为进程设置文件模式创建屏蔽字,并返回之前的值(umask设置文件创建时的默认权限,与chmod的效果刚好相反,==umask设置的是权限“补码”==,)
#include 
mode_t umask(mode_t cmask) ;
    //返回值,之前的文件模式创建屏蔽字
  • c-mask时图4.6中列出的9各常量

4.9 函数chmod,fchmod,fchmodat

  • 更改现有文件访问权限
    #include
    int chmode(const char *pathname, mode_t mode) ; //在指定文件上操作
    int fchmod(int fd,  mode_t mode) ;//对已经打开的文件操作
    int fchmodat(int fd, const char * pathname, mode_t mode, int flag); //上面两个的融合
    //成功返回0,失败返回-1
  • flag 参数可以用于改变fchmodat的行为,当设置了
  • mode是各种常量的按位或

4.10 粘着位 -----S_ISVTX

  • 如果对一个目录设置了粘着位,只有对该目录具有写权限的用户并且满足下列条件之一,才能删除或重命名该目录下的文件
    • 拥有该文件
    • 拥有此目录
    • 是超级用户

4.11 函数chown,fchown,fchownat和lchown

#include
int chown(const char * pathname, uid_t owner, gid_t group) 
int fchown(int fd, uid_t owner, gid_t group) 
int fchownat(int fd, const char *pathname, uid_t owner, gid_t group, int flag)
int lchown(const char * pathname, uid_t owner ,gid_t group)
  • lchown和fchown(设置了AT_SYMLINK_NOFOLLOW)更改符号链接本身的所有者
  • BSD的系统只有超级用户才能更改一个文件的所有者

4.12 文件长度

  • stat结构成员st_size表示以字节为单位的文件的长度
  • 文件空洞
    • 文件空洞由偏移量超过文件尾部后写入数据造成

4.13 文件截断

  • 需要在文件末尾截去一些数据以缩短文件
  • 打开文件的时候将O_TRUNC标志可以做到这一点
//将一个现有文件截为length
#Include 
int truncate(const char * pathname, off_t length )
int ftruncate(int fd, off_t length)
    //成功返回0,出错返回-1

4.14 文件系统

  • i-node 包含文件相关的所有信息:文件类型,文件访问权限位,文件长度,指向文件数据块的指针,stat结构的大多数信心取自i-node
  • mv命令构造一个新的i-node的目录项,然后删除老的目录项

4.15 函数link,linkat,unlink,unlinkat和remove

#indlude 
int link(const char *existingpath, const char *newpath)
int linkat(int efd, const char *existingpath, int nfd, const char * newpath, int flag)

4.16 函数rename和renameat


第5章 标准i/o库

5.1 引言

  • 令人惊讶的是,35年来,几乎没有对标准io库进行修改

5.2 流和FILE对象

  • 对于I/O函数都是围绕文件描述符的
  • 对于标准I/O库,所有的操作都是围绕流进行的,当用标准 I/O打开或创建文件的时候,我们已经使一个流和一个文件相关联
  • 流的定向决定了所读写的流使单字节的还是多字节(宽)字符的
  • 当流创建时为定向,对一个流使用单/多字节I/O函数,则该流被设置为相应的长度定向
  • 只有两个函数可以改变流的定向,freopen和fwide
    • freopen用于清楚流的定向
    • fwide用于设置流的定向
# include
#include
int fwide(FILE *fp, int mode) ;
    //返回值,若流为宽定向,返回正值,字节定向返回负值,未定项返回0
  • fwide不该变流的定向,无出错返回
  • 打开一个流的时候,返回一个指向FILE结构的指针,该指针包含所有流的信息,该指针也称为==文件指针==

5.3 标准输入,输出,错误

  • 对一个进程预定义了这三个流,通过预定义文件指针stdin,stdout,stderr加以引用

5.4 缓冲

  • 标准io提供缓冲的目的时尽可能少使用read,write.它对每个流进行自动的缓冲管理

  • 标准io提供一下三种缓冲

    • 全缓冲
      • 填满缓冲区后才进行实际io操作,驻留磁盘文件按通常全缓冲
      • flush说明标准io进行缓冲区的清洗操作,可由标准io自动冲洗
      • 调用fflush可以手动冲洗
    • 行缓冲
      • 在输入输出遇到换行符的受进行io操作
      • 行缓冲的限制
        • 标准io提供的行缓冲区时固定长度,填满缓冲区时没有换行符也进行io操作
        • 当从一个不带缓冲的流或一个行缓冲流得到输入数据,就会重复所有行缓冲流
    • 不缓冲
      • 不对字符进行缓冲存储
      • 标准错误不缓冲
  • 对任何一个给定的流,如果我们不喜欢这些系统默认,那么我们可以更改缓冲类型

//打开或关闭缓冲机制
void setbuf(FILE *restrict fp, char *restrict buf) ;    
//设置缓冲类型 
int setvbuf(FILE *restrict fp, char * restrict buf, int mode, size_t size) ;  
                                //成功返回0,错误返回-1
  • 上面的操作在流已被打开且应在操作流之前调用
  • 使用vsetbuf可以精确说明缓冲类型
    • _IOFBF
    • _IOLBF
    • _IONBF

5.5 打开流

#include
//打开pathname指定的文件
FILE *fopen(const char *restrict pathname, const char * restrict type) ;
//在一个指定的流上打开一个指定的问文件,若流已经打开,则先关闭该流
FILE *freopen(const char *restrict pathname, const char * restrict type,FILE * restrict fp) ;
//取一个已有的文件描述符,并使一个标准io流于该文件描述符结合(使用fd打开流)
//此函数常用于创建管道和网络通信通道函数返回的描述符
FILE *fdopen(int fd, const char *type) ;
        //成功返回文件指针,错误返回NULL

5.6 读和写流

  • 一旦打开了流,则可以使用三种类型的io进行读写操作
    • 一个字符的io

    • 每次一行的io
      • 使用fgets和fputs
    • 直接io
      • fread
      • fwrite
  • 输入函数
    • 一次读取一个字符
      #include 
      //可被实现为宏,所以调用时间更短
      int getc(FILE *fp) ;
      //一定是一个函数,可以得到地址
      int fgetc(FILE *fp) ;
      //等于 getc(stdin)
      int getchar(void) ;
          //成功,返回下一个字符,达到尾端或出错返回EOF    
          //这三个函数在返回下一个字符时,将其unsigned char转换为int 
      
      • 不论是出错还是达到结尾,这几个函数返回值都一样,所以需要下面的函数区分
          #include
          int ferror(FILE *fp) ;
          int feof(FILE *fp) ;
      
          void cleanerr(FILE * fp) ;
      
      • 为每个流在FILE对象中维护了两个标志
        • 出错标志
        • 文件结束标志
      • 调用cleanerr可以清楚这两个标志
    • 从流中读取数据后,可以调用ungetc将字符在压送回流中
        #include
        int ungetc(int c, FILE *fp) ;
            /成功返回c失败返回EOF
    
      -压送回流的字符又可以从流中读出
    
    • 压送回的字符没有写入设备而是写回标准io的缓冲区
  • 输出函数
    • 和输出相对应
    #include
    int putc(int c, FILE *fp) ; //可被实现为宏
    int fputc(int c ,FILE *fp) ;
    int putchar(int c) ;
    //成功返回c失败返回EOF

5.7 每次1行io

  • 输入
    #include
    //从指定的流中读,必须指定缓冲区的长度,缓冲区以null字节结尾
    char *fgets(char *restrict buf, int n, FILE *restrict fp) ;
    //从标准输入读
    char * gets(char *buf) ;
    //  成功返回buf,失败或到达尾端返回NULL
    //这两个函数都指定了缓冲区的地址,读入的行将送入其中
  • 输处
    #include
    //从指定的流中读,必须指定缓冲区的长度,缓冲区以null字节结尾
    char *fputs(char *restrict str, int n, FILE *restrict fp) ;
    //从标准输入读
    char * puts(const char *buf) ;
    //  成功返回非负值,失败返回EOF
    //这两个函数都指定了缓冲区的地址,读入的行将送入其中

5.8 标准io的效率

  • 尽量使用按行读取的

5.9 二进制io

  • 当需要读取一个结构或者对象的时候就不能使用按行和按字符读取
    size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp) ;
    size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp) ;
    // 返回读写的对象数
  • size使对象结构的sizeof,nobj应该使对象的个数,如果一个5各元素的数组,我希望读三个元素,则nobj为3

5.10 定位流

三种方法定位标准io流

  • ftell和fseek函数
  • ftello和fseeko
  • fgetpos和fsetpos

5.11 格式化io

5.12 实现细节

  • 每个标准io都要调用系统io
  • 每个标准io都有一个与其关联的文件描述符
int fileno(FILE *fp) ;
    //返回与流相关的文件描述符
  • 如果调用dup或者fcntl,则需要这个函数

5.13 临时文件

    #include
    char *tmpnam(char *ptr) ;
    FILE *tmpfile(void) ;
    //  成功返回文件指针,出错返回NULL
  • 上面两个文件用于创建临时文件
  • tmpfile函数经常先调用tempnam产生一个唯一的路径名,然后用改路径名创建一个文件,并立刻unlink它。
  • 关闭文件或程序结束时,临时文件自动删除

5.14 内存流

  • 标准io库把数据缓存在内存中
  • 可以调用setbuf或setvbuf让io库缓冲数据到我们自己的缓冲区
  • 三个函数用于内存流的创建
    FILE *fmemopen(void *restrict buf, size_t size, const char *restrict type) ;
    //成功返回流指针,错误返回NULL

5.15 标准io替代软件

第六章:系统数据文件信息

6.1 引言

  • 由于历史原因,系统一些数据文件都是ACSCII文本文件,且使用标准io库读这些文件
  • 本章主要介绍非ascii文本格式读取系统文件的接口
    6.2 口令文件
  • unix系统口令文件(用户数据库)包包含在定义的passwd结构中
  • 口令文件时/etc/passwd
  • 阻止一个用户登陆系统可以使用/dev/null或者/bin/false作为登陆shell,登录时以不成功终止
  • nobody表示任何人都可以i登陆系统,但是用户id和组id只能访问人人皆可读可写的权限

6.3 shadow passwd(阴影文件)

  • 现在的unix系统将加密后的密码放在另外一个文件中/etc/shadow。该文件至少包含用户名和加密口令。

6.4 组文件

unix组文件

6.5 附属组id

在unix系统中,附属组的优点时不必显式的更改组,一个用户参与多个项目,也就属于多个组。

6.7 其他数据文件

  • /etc/services --记录各网络服务器所提供服务的数据文件
  • /etc/protocols -- 记录 协议信息
  • /etc/networks -- 记录网络信息
  • 不同的口令文件需要使用不同的头文件来导入执行改文件的函数
    6.8 登陆账户记录
    utmp 文件记录当前登陆到系统的各个用户
    wtmp文件跟踪各个登陆和注销事件

6.9 系统标识

int uname(struct utsname *name) ;
  • 通过该函数的参数向其传递一个utsname结构的地址,然后该函数填写此结构。

6.10 时间和日期例程

  • unix内核提供的基本时间服务是计算自UTC时间以来经过的秒数,这个时间是日历时间

你可能感兴趣的:(APUE文件io)