硬链接,软链接,link,rename,symlink,opendir和readdir

article/2025/10/16 12:11:21

什么是硬链接

struct stat {nlink_t   st_nlink;       /* Number of hard links};

stat结构体就有一个成员变量----硬链接数

  • 使用ln命令就可以创建硬链接

  • 创建硬链接,就是再为文件创建一个名字

每创建一个硬链接,文件就多一个文件名,硬件链接数+1

  • 多个文件名指向了同一个文件,操作文件时,使用任何一个名字都可以

创建硬链接后所得到的多个文件名,指向的同一个inode节点,只有inode节点代表了文件的真实存在,inode节点只有一个,因此多个文件名指向的是同一个文件,不管使用的是哪一个文件名,都能操作这个文件。

硬链接数

  • 记录了有多少个文件名指向了inode节点,通过创建硬链接,每增加一个文件名,就多一个硬链接数
  • 同理,每删除一个硬链接,也就是删除一个文件名,就少一个硬链接数

删除文件时,只是将文件的inode节点空间释放了,如果这个文件有数据的话,那么这个文件的数据仍然还在,在这种情况下,只要将文件的inode节点空间恢复,即可还原该文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7fe3Diap-1667544982020)(/home/guojiawei/.config/Typora/typora-user-images/image-20221104144320671.png)]

如图,新创建的目录的硬链接数是2.

因为新创建的目录,一开始就有两个名字指向了目录的inode节点,分别是目录的本名text和.

  • 在该目录下,每多创建一个目录,当前目录就会多一个硬链数

Linux不允许用户自己给目录创建硬链接,只能由Linux系统自己给目录创建硬链接

用户只能给目录以外的,其它类型的文件创建硬链接

目录

目录是特殊的文件,本质上是一个表格,用于存储文件名和inode节点空间

可以在目录中创建多个链接指向文件,这些链接指向相同的inode节点空间

link函数

#include <unistd.h>
//功能:为非目录文件建立一个新的硬连接(ln命令就是调用这个系统函数来实现的)
//返回值:调用成功返回0,失败返回-1,errno被设置
int link(const char *oldpath, const char *newpath);
 link("./mm.txt","./mm1.txt");

unlink函数

#include <unistd.h>
//功能:删除一个硬连接,其实就是删除一个名字。	
//返回值:调用成功返回0,失败返回-1,errno被设置
//参数:pathname:要删除路径名
int unlink(const char *pathname);

只能用于删除非目录文件的硬链接,不能删除目录的硬链接,Linux系统不允许用户修改目录的硬件链接

使用unlink创建临时文件

临时文件:

  • 只在程序运行过程中有效,程序运行结束后就自动删除

  • 使用unlink就可以实现一个临时文件

open创建一个文件后(新文件的硬链接数都是1),然后立即调用unlink将文件硬链接数减为0,将其删除。

虽然文件的硬链接数变成了0,但是在进程没有结束之前,这个文件仍然可以被使用,直到进程结束后,文件才被删除

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(){int fd=open("mm.txt",O_RDWR|O_CREAT,0664);if(fd==-1){perror("open fail!");exit(-1);}unlink("./mm.txt");write(fd,"hello,world!\n",12);lseek(fd,0,SEEK_SET);char buf[30]={0};read(fd,buf,sizeof(buf));printf("buf=%s\n",buf);return 0;
}

remove函数

#include <stdio.h>
//功能:可以用于删除任何文件(既可以删除目录文件,也可以删除非目录文件)
//删除非目录文件时,功能与unlink一样。
//返回值:调用成功返回0,失败返回-1,errno被设置
int remove(const char *pathname);
int main(){remove("./aaa");//删除目录aaareturn 0;
}

rename函数

mv命令

  • 改名
  • 移动
  • 移动+改名

mv ./mm.txt …/mm_aa.txt

#include <stdio.h>
//功能:修改文件路径名,将旧的路径名oldpath,改为新的路径名newpath
//返回值:调用成功返回0,失败返回-1,errno被设置
int rename(const char *oldpath, const char *newpath);
rename("./mm_aa.txt","./aaa/mm.txt");//使用

如果文件移动起始位置和目标位置,在同一个分区里面的话

移动文件时,不会移动文件的数据;

只是把文件的基本信息(名字、inode编号),从这个目录记录到另一个目录下。

什么是符号链接

符号链接文件也被称为软链接文件

使用ln -s就可以创建符号链接文件

  • 符号链接文件就是一个快捷图标,它指向了另一个文件

和windows一样,原文件被删除了,快捷指向就没意义了


软链接和硬链接的对比

  • 创建硬连接

    同一个文件有多个不同的名字,它们指向是同一个inode节点

  • 创建符号链接文件

    符号链接文件与它所指向的文件,是两个完全不同的独立的文件,拥有自己独立的inode节点。

    符号链接文件的数据就是指向文件的文件名,文件大小就是名字的字符个数

不能给目录创建硬链接,但是可以给目录创建符号链接;只要你有需要,可以给任何文件创建符号链接文件。而且可以给符号链接文件,创建硬链接

s_link是link目录的软链接,p_s_link是s_link的硬链接

symlink

#include <unistd.h>
//功能:为oldpath,创建符号连接文件newpath
//函数返回值:调用成功返回0,失败返回-1,errno被设置
int symlink(const char *target, const char *linkpath);

使用ln创建硬链接时,调用的是link函数; 使用ln -s创建符号链接时,调用的是symlink

readlink

#include <unistd.h>
//功能:读符号链接文件的数据(指向文件的名字)
/*1)const char *path:符号连接文件的路径名。2)char *buf:存放名字缓存的地址。3)size_t bufsiz:缓存的大小
*/
//返回值:调用成功,返回读到的字节数,失败返回-1,errno被设置
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

int main(){symlink("./link.c","slink");char buf[30]={0};readlink("./slink",buf,sizeof(buf));printf("buf=%s\n",buf);return 0;
}

stat半成品

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void print_error(char *str){perror(str);exit(-1);
}int main(int argc, char **argv){int ret = 0;int i = 0;struct stat sta = {0};if(argc != 2){printf("./a.out fileName\n\n");exit(-1);}/* 获取文件属性 */ret = lstat(argv[1], &sta);if(-1 == ret) print_error("stat fail");/* 打印文件类型 */char file_type = '0';	if(S_ISLNK(sta.st_mode)) file_type = 'l'; else if(S_ISREG(sta.st_mode)) file_type = '-';else if(S_ISDIR(sta.st_mode)) file_type = 'd';else if(S_ISCHR(sta.st_mode)) file_type = 'c';else if(S_ISBLK(sta.st_mode)) file_type = 'b';else if(S_ISFIFO(sta.st_mode)) file_type = 'p';else if(S_ISSOCK(sta.st_mode)) file_type = 's';printf("%c", file_type);/* 打印文件权限 */	char buf[10] = {0};char tmp_buf[] = "rwxrwxrwx";for(i=0; i<9; i++){if(sta.st_mode & (1<<(8-i))) buf[i] = tmp_buf[i];else buf[i] = '-';}printf("%s", buf);/* 打印文件属性 */printf(" %lu %u %d %ld %ld %s", sta.st_nlink, \sta.st_uid, sta.st_gid, sta.st_size, sta.st_atime, argv[1]);//打印出链接文件的指向if(file_type=='l'){char mm[30]={0};readlink(argv[1],mm,sizeof(mm));printf("->%s\n",mm);}else printf("\n");return 0;
}

符号跟随函数 与 符号不跟随函数

(1) 符号跟随函数

调用某个函数操作文件,当指定的路径名是符号链接文件时:

如果函数最后操作的是符号链接文件所指向的文件,而不是“符号链接文件”本身,

这个函数就是符号跟随函数,因为它跟到符号链接文件所指向的背后去了。

  • 比如stat、open就是符号跟随函数,因为这些操作的都是符号链接文件所指向的文件

(2)符号不跟随函数

当路径名是符号链接文件时,函数操作的就是符号链接文件本身,不会跟随

比如lstat就是符号不跟随函数,因为获取文件属性时,如果操作的是符号链接文件的话,那么获取的是符号链接文本身的属性。

  • 凡是需要指定“文件路径名”函数,只要函数名字是l打头的,比如像lstat,基本都是符号不跟随函数。
  • lseek不需要指定路径名,而是通过文件描述符(fd)操作的,不存在符号跟随与不跟随的问题。

getcwd

#include <unistd.h>
//这是一个库函数,执行pwd命令就是调用这个函数实现的
//功能:获取进程的当前工作目录
/*参数1)buf:存放获取到的当前路径的缓存2)size:缓存的大小
*/
char *getcwd(char *buf, size_t size);
int main(){char buf[30]={0};char *p=getcwd(buf,100);printf("pwd=%s\n",buf);printf("p=%p,buf=%p\n",p,buf);return 0;
}
/*执行结果:
pwd=/home/guojiawei/Desktop/link
p=0x7ffe8d093ac0,buf=0x7ffe8d093ac0
getcwd的返回值是存放路径的地址
*/

chdir

change chdir

#include <unistd.h>
//功能:切换进程当前工作目录到path。
int chdir(const char *path);
int main()
{char buf[30] = {0};char *p = getcwd(buf, 100);printf("pwd=%s\n", buf);chdir("../");getcwd(buf, 100);printf("pwd_cur=%s\n", buf);return 0;
}
/*执行结果:
pwd=/home/guojiawei/Desktop/link
pwd_cur=/home/guojiawei/Desktop
*/

cd命令就是调用chdir的命令

mkdir

#include <sys/stat.h>
#include <sys/types.h>
//功能:创建新目录。
/*参数:1)pathname:需创建目录的路径名2)mode:指定目录的原始权限,一般给0775
*/
int mkdir(const char *pathname, mode_t mode);

给目录指定原始权限时,一定要有x权限,否者无法进入这个目录

rmdir

rm命令删除目录时,调用的都是rmdir这个函数

  • rmdir命令:只能删除空目录,rmdir命令用的很少
  • rm:不管目录空不空,都能删除,rm用的最多
	                 rm|remove|     ||     |/       \/         \unlink 	     rmdir
#include <unistd.h>
//函数功能:删除路径名为pathname的这个目录
int rmdir(const char *pathname);

删除时,Linux系统会调用相关函数,将目录硬链数全部减位0,然后目录就被删除了

如果目录不为空,必须递归调用rmdir函数,实现递归删除

opendir和readdir

  • opendir:打开目录,以便调用readdir读取目录项
  • readdir:读取目录里面的目录项

目录项:
目录里面的数据,其实就是一条一条的目录项,每个目录项就是一个文件的基本信息

文件基本信息:文件名inode节点号

不能使用open函数打开目录,只能使用opendir打开

#include <sys/types.h>
#include <dirent.h>
//功能:打开目录
//参数:name---需打开目录的路径名
/*返回值:调用成功:返回一个DIR *的指针,这个指针指向了被打开的目录,readdir通过这个指针就可以读取目录的目录项。调用失败:返回NULL,errno被设置。
*/
DIR *opendir(const char *name);
#include <dirent.h>
//功能:读取目录里的目录项-----每调用一次,就读取出一条目录项。
//参数dirp:opendir打开目录时,得到的指针。
//返回值:调用成功,返回指针指向struct dirent结构体的指针
/*
返回NULL的话有如下两种情况:1)读到目录的末尾时,返回NULL。2)函数调用失败时,也返回NULL,不过errno被设置。	
*/
struct dirent *readdir(DIR *dirp);
  • 结构体 struct dirent

    这个结构体就是用来存放一条目录项的:

    调用readdir读取到目录项后,会自动开辟一个struct dirent变量来存放目录项,然后将变量的指针返回;

    应用程序通过这个指针,就可以访问结构体中的目录项信息(文件基本信息)。

    struct dirent {ino_t          d_ino;       /* Inode number */off_t          d_off;       /* Not an offset; see below */unsigned short d_reclen;    /* Length of this record */unsigned char  d_type;      /* Type of file; not supportedby all filesystem types */char           d_name[256]; /* Null-terminated filename */};
    //最重要的就是:inode编号和文件名
    

    怎么判断函数是否调用失败了呢?

    • 如果ernno==0,表示没有设置错误号,返回NULL是因为读到了文件的末尾。
    • 如果errno!=0,表示是因为函数调用出错而返回的NULL。
#include <stdio.h>
#include <stdlib.h>
//opendir头文件
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>int main(){DIR *pot=opendir(".");if(pot==NULL){perror("opendir fails!");exit(-1);}while(1){//循环读struct dirent *dir_p=readdir(pot);if(dir_p==NULL && errno!=0){perror("readdir fails\n");}if(dir_p==NULL && errno==0) break;//读到末尾printf("inode=%lu,fname=%s\n",dir_p->d_ino,dir_p->d_name);}return 0;
}

chmod 和 fchmod

#include <sys/stat.h>
//功能:修改文件权限
//chmod:使用路径名操作
//fchmod:使用文件描述符操作
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);

http://chatgpt.dhexx.cn/article/IOPKHj5S.shtml

相关文章

符号链接symlink_什么是符号链接或符号链接? 如何为Windows和Linux创建Symlink?

符号链接symlink Symbolic Links are also known as Symlinks. Symlinks are used to create a shortcut for a given file or folder. Symlinks are very useful for different purposes which also prevents copy the same data over and over again. In this tutorial, we w…

Visual Studio2019使用nmake编译调用libcurl库

编译 1.下载地址&#xff1a; curl downloads 我下载的是7.61.0 2.编译&#xff1a; 使用的是&#xff1a;VS2019 x64 本机工具命令提示&#xff0c;当然如果想编译成X86的库&#xff0c;可以选择VS2013 x86 本机工具命令提示或者VS2019 x64 兼容工具命令提示。 打开VS201…

cl.exe nmake.exe

1. 如果已经有vc6的dsp工程&#xff0c;可直接导出nmake脚本文件(.mak) “Project - Export Makefile...” nmake -f nMakeTest.mak CFG"nMakeTest - Win32 Debug" nmake -f nMakeTest.mak CFG"nMakeTest - Win32 Debug" all nmake -f nMakeTest.mak CFG&q…

Windows环境下用nmake编译libevent

Windows环境下用nmake编译libevent 一、方法总结1) nmake 命令找不到2) 头文件找不到3) lib库找不到4) 不知道如何生成“print-winsock-errors.obj” 二、详细说明1、nmake 和 cl 命令2、各种头文件缺失3、lib 库无法打开4、“print-winsock-errors.obj” 三、结语 最近在将一个…

nmake、makefile、cmake学习笔记

1.nmake 1.1 nmake reference NMAKE.EXE是Visual Studio附带的一个命令行工具&#xff0c;它基于描述文件中包含的命令生成项目。 要使用NMAKE&#xff0c;必须在开发人员命令提示符窗口中运行它。开发人员命令提示符窗口为工具、库设置了环境变量&#xff0c;并包含在命令行…

cmake nmake qmake 的区别联系

&#x1f447;推荐关注&#x1f447; 经常记不住这几个概念&#xff0c;都看了几次了还是容易忘&#xff0c;为以后方面查阅&#xff0c;故而从知乎上复制粘贴过来。 1、gcc是GNU Compiler Collection&#xff08;就是GNU编译器套件&#xff09;&#xff0c;也可以简单认为是编…

VC++NMAKE

目 录 第1章 NMAKE 1 1.1 运行NMAKE 1 1.1.1 NMAKE的实质 2 1.2 描述块 3 1.2.1 定义 3 1.2.2 多个描述块 3 1.2.3 依赖 4 1.2.4 长文件名 4 1.2.5 多目标 4 1.2.6 合并 5 1.3 宏 5 1.3.1 定义、使用 5 1.3.2 作…

WINDOWS CMAKE与NMAKE

什么是cmake 你或许听过好几种 Make 工具&#xff0c;例如 GNU Make &#xff0c;QT 的 qmake &#xff0c;微软的 MSnmake&#xff0c;BSD Make&#xff08;pmake&#xff09;&#xff0c;Makepp&#xff0c;等等。这些 Make 工具遵循着不同的规范和标准&#xff0c;所执行的…

vs 编译nmake工程

以本人电脑为例&#xff1a; 1、将D:\program files\visual studio 2013\VC\bin这个路径添加到系统环境变量的path中 2、打开cmd的控制台命令行界面 输入nmake与cl来测试是否报错 3、编译make文件&#xff1a; cd到源文件所在目录&#xff0c;使用命令nmake /F *.nmake编译m…

nmake 环境变量配置

本农有3年多C/C开发经验,最近面试全部翻车,总结原因是基础知识不过关,于是最近在看C primer 5,配套的源代码编译没通过,原因是nmake需要配置环境变量,总结错误如下 1.找不到nmake命令 解决方法:找到nmake所在路径,我用的是vs2010,C:\Program Files (x86)\Microsoft Visual Stud…

nmake命令(windows下的makefile)

1. 如果已经有vc6的dsp工程&#xff0c;可直接导出nmake脚本文件(.mak) “Project - Export Makefile...” nmake -f nMakeTest.mak CFG"nMakeTest - Win32 Debug" nmake -f nMakeTest.mak CFG"nMakeTest - Win32 Debug" all nmake -f nMakeTest.mak CFG&q…

nmake简介

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 nmake学习初步 前言一、nmake在哪里&#xff1f;二、Makefile编写1.hello.c实例代码2. Makefile3 扩展 前言 一直使用vs的IDE&#xff0c;最近编译sqlcipher时&#xff0c;发…

第八章 查询和检索:Query DSL

版权声明 本文为Elastic开源社区版权所有,保证独立性和原创性,未获得授权和允许,任何组织和个人不得以任何方式传播或复制或分享。否则必将追究法律责任。 知识内容输出不易,请尊重他人劳动成果。严禁随意传播、复制和盗用他人成果或文章内容用以商业或盈利目的! 1、查询…

mysql-dql(Data QueryLanguage)summary

1.基础查询 DESC 库名//查看库SHOW DATABASES ;//查看当前所在数据库SHOW TABLES;//查看当前库的所有表USE database;//datebase为需要查询的库名SELECT attribute,attribute2 FROM form;//从form中查询attribute,attribute2SELECT * FROM beauty;//查询表中所有属性SELECT DI…

db.query的使用

首先假设有如下表格&#xff0c;表格名称为&#xff1a;"Employees" SQL基本格式如下&#xff1a; [sql] view plain copy print ? select 列名称 from 表名称 最基本SQL语句&#xff0c;就是从表中选取要返回的列数据&#xff0c;不加任何过滤条件。当然如果&qu…

Elasticsearch——Query DSL语法入门

Query DSL入门 官网介绍链接&#xff1a; https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html search api就是对存储在elastic search&#xff08;以下简称es&#xff09;中的数据进行查询的相关API&#xff0c;可以类比mysql中的select语句。…

Data Query Language(DQL):数据查询语言

Data Query Language&#xff08;DQL&#xff09;&#xff1a;数据查询语言 基础查询查询所有列查询指定列 条件查询条件查询介绍查询示例如下 模糊查询模糊查询介绍查询示例如下 字段控制查询排序聚合函数分组查询分页查询 建立三张表用于查询&#xff0c;表中数据如下。 stu表…

SpringDataJPA+QueryDSL玩转态动条件/投影查询

在本文之前&#xff0c;本应当专门有一篇博客讲解SpringDataJPA使用自带的SpecificationJpaSpecificationExecutor去说明如何玩条件查询&#xff0c;但是看到新奇、编码更简单易懂的技术总是会让人感到惊喜&#xff0c;而且QueryDSL对SpringDataJPA有着完美的支持。如果你没有使…

ES的Query DSL语句介绍

1、term 过滤 term主要用于精确匹配哪些值&#xff0c;比如数字&#xff0c;日期&#xff0c;布尔值或 not_analyzed 的字符串(未经切词的文本数据类型)&#xff1a; { "term": { "date": "2017-07-01" }} { "term": { "tit…

QueryDSL配置

QueryDSL配置 1&#xff1a;maven配置- <dependency><groupId>com.querydsl</groupId><artifactId>querydsl-jpa</artifactId><version>5.0.0</version></dependency><dependency><groupId>com.querydsl</gro…