Linux环境编程之文件I/O(八):文件链接

引言:

执行如下命令时,

ls /usr/local/lib/libfreetype.so -l

显示内容:

lrwxrwxrwx 1 root root 20 2014-04-06 22:57 /usr/local/lib/libfreetype.so -> libfreetype.so.6.9.0

表明这是一个链接文件,通过链接可以实现对一个文件从不同路径对它进行引用。对于文件的链接有硬链接和软连接(即符号链接)之分。shell中的ln命令可以创建一个文件的硬链接,加上-s选项可以创建一个文件的软链接。要想深入的理解文件链接的概念,必须先明白文件系统的基本结构以及i节点和指向i节点的目录项之间的区别。因此,先要对文件系统的基本结构做下了解,然后分别深入了解文件的硬链接与软连接。最后,了解一下文件的修改时间。

(一):文件系统的基本结构

每个磁盘可以分成一个或多个分区,每个分区可以包含一个文件系统。文件系统的基本结构如下图:

其中i结点是固定长度的记录项,它包含有关文件的大部分信息。

比较详细的柱面组的i结点和数据块部分如下图:

首先,目录、目录项、索引节点的关系是:

一个目录文件包含了一组目录项,目录项放在数据块中。一个目录项主要包括文件名和索引节点号,索引节点号是指向索引节点表中对应的索引节点的。也可这样理解目录项:因为目录可以包含子目录,目录是可以层层嵌套的,所以形成文件路径,而文件路径中的每一部分就是所谓的目录项。索引节点是文件系统处理文件所需要的所有信息都存放在称为索引节点的数据结构中。主要就是文件的属性,包括链接数、文件所有者、文件建立和修改时间,文件在磁盘的位置,文件大小,使用权限等。

对于上面的两图,应注意以下几点:

1、在图中有两个目录项指向同一i节点。每个i节点中都有一个链接计数,其值是指向该i节点的目录项数。只有当链接计数减小至0时,才可删除该文件(即释放该文件占用的磁盘块)。这就是为什么“解除一个文件的链接”操作并不总是意味着“释放该文件占用的磁盘块”的原因。这也是为什么删除一个目录项的函数被称为unlink而不是delete的原因。在stat结构中,链接计数包含在st_nlik成员中,这种链接类型称为硬链接。

2、另外一种链接类型称为符号链接。对于这种链接,该文件的实际内容(在数据块中)包含了该符号链接所指向的文件的名字。

3、i节点包含了大多数与文件有关的信息:文件类型、文件访问权限位、文件长度和指向该文件所占用的数据块的指针等等。stat结构中的大多数信息都取自i节点。只有两项数据存放在目录项中:文件名和i节点编号。

4、每个文件系统各自对它们的i节点进行编号,因此目录项中的i节点编号数指向同一文件系统中的相应i节点,不能使一个目录项指向另一个文件系统的i节点。这就是为什么ln命令不能跨越文件系统的原因。

5、当在不更换文件系统情况下为一个文件更名时,该文件的实际内容并未移动,只需要构造一个指向现有i节点的新目录项,并解除与旧目录项的链接。

(二)link、unlink、remove、rename函数

上面的函数都是针对硬链接进行操作的。关于硬链接,应该注意一下几点:

1、建立硬链接时,一定要在同一文件系统内执行。

2、对于目录,通常的文件系统实现不允许建立硬链接,即使能够建立,也仅限于超级用户才能这样做。

3、删除目录项时pathname时,会使的pathname所引用文件的链接计数减1。如果还有指向该文件的其他链接,则仍可通过其他链接访问该文件的数据。

4、为了解除对文件的链接,必须对包含该目录项的目录具有写权限和执行权限。

5、只有当链接计数达到0时,该文件的内容才可能被删除。另一个阻止删除文件的条件是有进程打开该文件,其内容也不能被删除。关闭一个文件时,内核首先查看打开该文件的进程数,如果该数达到0,然后内核检查其链接数,如果这个数也是0,那么就删除该文件的内容。

#include <unistd.h>

int link(const char *oldpath, const char *newpath); // 若成功则返回0, 若出错则返回-1。

此函数创建一个新目录项newpath,它引用现有的文件existingpath。如果newpath已经存在,则返回出错。只创建newpath中的最后一个分量,路径中的其他部分应当已经存在。

#include <unistd.h>

int unlink(const char *pathname); // 过成功则返回0,若出错则返回-1

此函数删除目录项,并将由pathname所引用文件的链接数减1.如果还有指向该文件的其他链接,则仍可通过其他链接访问该文件的数据。如果出错,则不对该文件做任何更改。

(三)

符号链接时指向一个文件的间接指针,它与上面所说的硬链接有所不同,硬链接直接指向文件的i节点。引入符号链接的原因是为了避开硬链接的一些限制:

1、硬链接通常要求链接和文件位于同一文件系统中。

2、只有超级用户才能创建指向目录的硬链接。

对符号链接以及它所指向何种对象并无任何文件系统限制,任何用户都可创建指向目录的符号链接。符号链接一般用于将一个文件或整个目录结构移动到系统的另一个位置。

#include <unistd.h>

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

#include <unistd.h>

ssize_t readlink(const char *path, char *buf, size_t bufsiz);

(四)

对每个文件都有3个时间字段。如下表:

字段 说明 例子 ls选项
st_atime

st_mtime

st_ctime

文件数据的最后访问时间

文件数据的最后修改时间

i节点状态的最后更改时间

read

write

chmod/chown

-u

默认

-c

注意修改时间和更改状态的时间之间的区别。修改时间是文件内容最后一次被修改的时间。更改状态时间是该文件的i节点最后一个被修改的时间,例如更改文件的访问权限、用户ID、链接数等。但它们都没有修改文件的内容。因为i节点中的所有信息都是与文件的时间内容分开存放的,所以,除了文件数据修改时间外,还需要更改状态时间。

#include <sys/types.h>

#include <utime.h>

int utime(const char *filename, const struct utimbuf *times);

struct utimebuf{

time_t actime;

time_t modtime;

}

此函数的操作以及执行它所需要的特权取决于time参数是否为NULL

1、如果times是一个空指针,则访问时间和修改时间两者都设置为当前时间。为了执行此操作必须满足下列两条件之一:进程的有效用户ID必须等于该文件的所有者ID;或进程对该文件必须具有写权限。

2、如果times是非空指针,则访问时间和修改时间被设置为times所指向结构中的值。此时进程的有效用户ID必须等于该文件的所有者ID,或者进程必须是一个超级用户进程。对文件只具有写权限是不够的。

Linux环境编程之文件I/O(八):文件链接

时间: 2024-12-29 11:14:01

Linux环境编程之文件I/O(八):文件链接的相关文章

Linux环境编程之文件I/O(六):文件属性

引言: 在Linux中使用ls -l filename命令查看filename的属性时,会列出文件的9种属性,例如:ls -l /etc/fstab -rw-r--r-- 1 root root 1102 2013-10-12 02:33 /etc/fstab 从左到右分别是类型与权限.文件个数.该文件或目录的拥有者.所属的组.文件大小.创建时间.文件名 以上这些文件属性的信息,都存放在一个stat的结构体中.下面就来分析一下这个结构体. 要想查看一个文件的stat结构体,可以通过stat类函数

Linux环境编程之文件I/O(四):文件I/O的数据结构

(一) Linux系统支持不同进程间共享打开的文件.内核使用三种数据结构表示打开的文件:进程表项.文件表项.v节点表. 1.进程表项:每个进程在进程表中都有一个记录项,记录项中年包含有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项.与每个文件描述符相关联的是: a.文件描述符标志 b.指向一个文件表项的指针 2.内核为所有打开文件维持一张文件表.每个文件表项包含: a.文件状态标志,如读写.添加.同步和非阻塞等. b.当前文件偏移量 c.指向该文件v节点表项的指针 3.每个打开的文

Linux环境编程之文件I/O(七):目录文件及操作

什么是数据结构? 数据结构是相互之间存在一种或多种特定关系的数据元素的集合. 还有一些概念(数据.数据元素.数据项.数据对象.数据类型...) 传统上,我们把数据结构分为逻辑结构和物理结构. 逻辑结构:是指数据对象中数据元素之间的相互关系,也是我们今后最需要关注和讨论的问题. 物理结构:是指数据的逻辑结构在计算机中的存储形式. 逻辑结构分为以下四种: 1.集合:集合结构中的数据元素除了同属于一个集合外,之间没有任何关系. 2.线性结构:元素之间一对一. 3.树形结构:一对多. 4.图形结构:多对

Linux环境编程之文件I/O(五):fcntl函数

引言: 对于一个普通的文件,我们可以想到的对它的操作有,读取文件的内容.写数据到文件中,这些都是前面提到的read.write函数的作用.除此之外,还可以获取文件的其他性质,并对这些性质进行修改,比如文件的描述符.文件描述符标记.文件状态标志等等.这些对文件性质的修改就由fcntl函数完成. 函数介绍: #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 参数: fd:

Linux环境编程之文件I/O(二):文件的打开与关闭

(一) Linux系统中,要对一个文件进行任何操作,必须首先获得它的文件描述符.而获得文件描述符的方式就是利用open/creat函数打开/创建该文件,open/creat函数返回文件描述符. #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, in

Linux环境编程之文件I/O(一):文件描述符

(一) 首先,对于内核来讲,它是利用"文件描述符"来访问文件的.文件描述符一般是一个非负的整数.当我们用open打开已有的文件或者用creat创建新的文件时,都会返回一个文件描述符.有了文件描述符之后,我们就可以利用该文件描述进行文件的读写,即read.write系统调用都需要文件描述符fd(file descriptor)作为其参数.从以上描述可以看出,当我们想要用read.write等系统调用对文件进行读写等操作之前,必须用open或creat系统调用得到文件的描述符. 一般Uni

Linux环境编程之文件I/O(三):文件的读写

(一) 当我们打开了一个文件后,一般对文件的操作就是读写.读写函数分别是read.write. #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); 参数: fd:利用open.creat得到的文件描述符. buf:buf是void *类型,用于表示通用指针,此处指所读取到的数据的内存缓冲. count:需要读取的数据量. 返回值:成功执行时,返回所读取的数据的字节数,一般等于或小于所请求读取的数据字节数.若已到文

Linux环境编程之共享内存区(一):共享内存区简介

Spark生态圈,也就是BDAS(伯克利数据分析栈),是伯克利APMLab实验室精心打造的,力图在算法(Algorithms).机器(Machines).人(People)之间通过大规模集成,来展现大数据应用的一个平台,其核心引擎就是Spark,其计算基础是弹性分布式数据集,也就是RDD.通过Spark生态圈,AMPLab运用大数据.云计算.通信等各种资源,以及各种灵活的技术方案,对海量不透明的数据进行甄别并转化为有用的信息,以供人们更好的理解世界.Spark生态圈已经涉及到机器学习.数据挖掘.

Linux环境编程之共享内存区(二):Posix共享内存区

现在将共享内存区的概念扩展到将无亲缘关系进程间共享的内存区包括在内.Posix提供了两种在无亲缘关系进程间共享内存区的方法: 1.内存映射文件:由open函数打开,由mmap函数把得到的描述符映射到当前进程地址空间中的一个文件.(上一节就是这种技术) 2.共享内存区对象:由shm_open打开一个Posix名字(也许是在文件系统中的一个路径名),所返回的描述符由mmap函数映射到当前进程的地址空间.(本节内容) Posix共享内存区涉及以下两个步骤要求: 1.指定一个名字参数调用shm_open