Linux系统编程(第八章)笔记

文件和目录管理

文件及其元数据

   所有文件对应一个inode(索引节点),它是由文件系统中唯一数值编址,该数值称为inode编号。inode既是位于UNIX式的文件系统的物理对象,也是在Linux内核数据结构描述的概念实体。inode存储了与文件有关的元数据,例如文件的访问权限、最后访问时间戳、所有者、用户组、大小以及文件数据的存储位置。
   可以使用ls命令的-i选项来获取一个文件的inode编号。
   unix提供的获取文件元数据的函数:

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>

int stat(const char *path,struct stat *buf);
int fstat(int fd,struct stat *buf);
int lstat(const char *path,struct stat *buf);

   以上这些函数都是把用户提供的信息保存在stat结构体中:

struct stat{
          dev_t st_dev;          /*设备节点*/
          ino_t st_ino;          /*inode编号*/
          mode_t st_mode;        /*文件权限*/
          nlink_t st_nlink;      /*硬链接数*/
          uid_t st_uid;          /*用户ID*/
          gid_t st_gid;          /*组ID*/
          dev_t st_rdev;         /*设备节点信息*/
          off_t st_size;         /*文件字节数*/
          blksize_t st_blksize;  /*用户缓冲I/O最佳块大小*/
          blkcnt_t st_blocks;    /*分配给文件的块数目*/
          time_t st_atime;       /*最新的文件访问时间*/
          time_t st_mtime;       /*最新的文件修改时间*/
          time_t st_ctime;       /*最新的文件状态改变时间*/
}

   设置权限的系统调用函数:

#include<sys/types.h>
#include<sys/stat.h>

int chmod(const char *path,mode_t mode);
int fchmod(int fd,mode_t mode);

   改变所有权的函数:

#include<sys/types.h>
#include<unistd.h>

int chown(const char *path,uid_t owner, gid_t group);
int lchown(const char *path,uid_owner,gid_t group);
int fchown(int fd,uid_owner,gid_t group);
目录

   在unix中,目录是个简单的概念:它包含一个文件名列表,每个文件名对应一个inode编号。每个文件名称为目录项,每个名字到inode的映射称为链接。目录内容(用户执行ls命令所看到的内容)就是该目录下所有文件名列表。当用户打开指定目录下的文件时,内核会在该目录列表中查找文件名所对应的inode编号,并将该inode传递给文件系统,文件系统使用它来寻找文件在设备上的物理位置。
   目录还能包含其他目录。子目录是在另一个目录里的目录。基于这个定义,除了文件系统树真正的根目录/外,所有目录都是某个父目录的子目录。
   获取当前工作目录的首选方法是使用POSIX的标准系统调用getcwd():

#include<unistd.h>

char * getcwd(char *buf,size_t size);

   Linux提供了两个系统调用来更改当前工作目录,一个接受目录路径名,而另一个接受指向已打开目录的文件描述符:

#include<unistd.h>

int chdir(const char *path);
int fchdir(int fd);

   Linux为创建新的目录提供了一个标准的POSIX系统调用:

#include<sys/stat.h>
#include<sys/types.h>

int mkdir(const char *path,mode_t mode);

   删除目录:

#include<unistd.h>

int rmdir(const char *path);

   查看目录内容的系统调用一般是使用C库的系统调用opendir(),readdir()和closedir()。

链接

   链接本质上不过是列表(目录)中一个指向inode的名字,从这个定义来看,并没有限制一个inode的链接的数目。因此单个inode(或者说单个文件)可以同时由两个或多个文件名指向(在同一个文件系统)。

硬链接

   我们称这种类型的链接为硬链接。文件的链接数可以是0、1或多个。大多数文件的链接数是1,也就是说只有一个目录项指向该文件,但有些文件可能有两个或甚至多个链接。链接数为0的文件在文件系统上没有对应的目录项。当文件链接计数达到0时,文件被标记为空闲,其占用的磁盘块就可重用。当进程打开了这样一个文件时,文件仍在文件系统中保留。如果没有进程打开该文件,文件就会被删除。
   Linux内核通过“链接计数”和“使用计数”来进行管理。使用计数是指文件被打开的实例数的计数。只有当某个文件的链接计数和使用计数都为0时,该文件才会从文件系统中删除。

#include<unistd.h>

int link(const char *oldpath, const char *newpath);

   成功调用link()会为oldpath所指向的已存在的文件,在路径newpath下创建新的链接,并返回0。调用完成后,oldpath和newpath都会指向同一个文件——实际上,我们无法区分哪个是“初始”链接。

符号链接

   符号链接,也称为symlinks或软连接。它和硬链接的相同之处在于二者均指向文件系统中的文件,不同点在于符号链接不会增加额外的目录项,而是一种特殊的文件类型。该文件包含被称为符号链接指向的其他文件(一般称为符号链接的目标文件)的路径名。运行时,内核用该路径名代替符号链接的路径名(除非使用系统调用是以“l”开头的系统调用,例如lstat(),它操作链接本身而非目标文件)。因此,一个硬链接与指向同一文件的另一个硬链接很难区分,但很容易区分符号链接以及其目标文件。
   软链接和硬链接相比,很重要的一个区别点在于它可以跨越不同的文件系统。实际上,软链接可以指向任何位置!符号链接能指向已存在(通常用法)或不存在的文件。后者被称为“悬空的符号链接(dangling symlink,或称无效的符号链接)。有时,悬空的符号链接是指不再需要的——例如当链接目标已删除,但符号链接没有删除时,该符号链接就变成悬空的了——但是,在某些情况下是故意的。符号链接还可以指向其他符号链接,这样就会存在环。处理符号链接的系统调用通过维护最大遍历深度来查看是否存在环。如果超过深度,就返回ELOOP。

#include<unistd.h>

int symlink(const char *oldpath, const char *newpath);

symlink()调用成功时,会创建符号链接newpath,指向由oldpath所表示的目标文件,并返回0.

解除链接
#include<unistd.h>

int unlink(const char *pathname);

   unlink()调用成功时,会从文件系统删除pathname,并返回0.
   为简化对各种类型文件的删除,C语言提供函数remove():

#include<stdio.h>

int remove(const char *path);

   成功调用remove()时,会从文件系统删除path,并返回0。如果path是个文件,remove()会调用unlink();如果path是个目录,remove()会调用rmdir()。

拷贝和移动文件

   两个最基本的文件处理任务是拷贝和移动文件,往往是通过命令cp和mv来实现。在文件系统层,拷贝是在新路径名下拷贝给定文件内容的行为。与创建文件新的硬链接不同的是,对一个文件的改变将不会影响另一个——也就是说,在(至少)两个不同目录项下,保存文件的两份独立拷贝。移动是在文件所在位置下重命名目录项的行为。该行为不会触发创建另外一个拷贝备份的操作。

拷贝

   要拷贝src,生成dst,执行以下步骤:

  1. 打开src。
  2. 打开dst,如果dst不存在则创建,如果已存在则把其长度阶段为零。
  3. 把src数据块读取至内存。
  4. 把该数据块写入dst。
  5. 继续操作直到src全部读取完且已经都写入到dst中。
  6. 关闭dst。
  7. 关闭src。
移动

   和拷贝文件操作不同,UNIX还提供了移动文件的系统调用。ANSI C标准中介绍了关于多文件操作的调用,POSIX标准中对多文件和目录操作都支持:

#include<stdio.h>

int rename(const char *oldpath,const char *newpath);

   成功调用rename()时,会将路径名oldpath重命名为newpath。文件的内容和inode保持不变。oldpath和newpath必须位于同一文件系统中,否则调用会失败。类似mv的工具必须通过调用拷贝和解除链接来完成rename操作。

带外通信
#include<sys/ioctl.h>

int ioctl(int fd,int request,...);

   该系统调用需要两个参数:
   fd 文件的文件描述符。
   request 特殊请求代码值,该值由内核和进程预定义,它指明对fd所指向的文件执行哪种操作。
   它还可能接收一个或多个隐式可选参数(通常是无符号整数或指针),并传递给内核。

监视文件时间

   Linux提供了一个监视文件的接口inotify——通过该接口可以监控文件的移动、读取、写入或删除操作。假设你正在编写一个类似GNOME’s Nautilus的图形化文件管理器。如果文件已拷贝至目录,而且Nautilus正在显示目录内容,则该目录在文件管理器中的视图将会出现不一致。
   通过inotify,内核能在事件发生时把事件推送给应用程序。一旦文件被删除,内核立刻通知Nautilus。Nautilus会做出响应,直接从目录的图形化显示中删除被删除的文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值