热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Linuxunlink函数和删除文件的操作方法

这篇文章主要介绍了Linuxunlink函数和删除文件的操作方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

1. unlink函数

  对于硬链接来说,unlink 用来删除目录项,并把 inode 引用计数减 1,这两步也是一个原子过程。直到 inode 引用计数为 0,才会真正删除文件。

  对于软链接来说,unlink 直接删除软链接,而不影响软链接指向的文件。

函数原型:

int unlink(const char *pathname);  

参数说明:

  pathname:指定要移除的链接文件

返回值说明:

  成功返回0;失败则返回-1,同时设置errno为相应值

2. 实验代码—myunlink

#include 
#include 
#include 
int main(int argc, char *argv[]){ 
 //为一个已经存在的文件创建目录项(硬链接)
 if(link(argv[1], argv[2]) == -1){
 perror("link error");
 exit(1);
 }
 //删除之前的文件目录项
 if(unlink(argv[1]) == -1){
 perror("unlink error");
 exit(1);
 }
 return 0;
}

  当我们执行./myunlink hellotest命令完后,会删除 hellotest,同时 inode 引用计数减 1。

3. 删除文件

  不用说,相信大家都用过rm -rf命令吧。

  现在我们再来思考一下,以前我们通过rm命令删除文件时你有没有质疑过,文件真的被删除掉了吗?

  如果真的删除的了话,那么操作系统又是怎么把文件删除掉的?

  操作系统在设计的时候是通过把文件的inode索引号与磁盘中的block块建立了关联,这样我们通过文件找到block块的位置,也就看到了文件的数据了。

  在删除文件时,是由系统的2个变量来控制的一个是i_link,表示文件的硬链接数量,另一个是i_count,表示文件的引用计数,文件删除的必需条件就是i_link = 0和i_count = 0。

  在磁盘中的文件只要把i_link = 0(硬链接数干掉)就可以把文件删除了,如果这个文件在程序中被打开,我们还需要把运行的程序干掉 i_count = 0,这样才能达到删除文件的目的。

4. linux下删除文件的大概过程

  linux下文件删除过程大概如图: 

这里写图片描述 

图1-linux下文件删除的大概过程

  当前磁盘中的/test/file目录下有一个test文件(i_link = 1),还有一个硬链接文件hard_link指向test文件(i_link = 1),且./test进程又打开了test文件(i_count = 1),如果要删除test.txt文件,必须把./test进程干掉(i_count = 0),然后删除hard_link硬链接文件和/test/file目录下的test.txt文件(也就是让i_link = 0)。

  也就是说linux下是通过link的数量来控制文件删除的,当一个文件的link = 0时,这个文件才会被删除。一般一个文件有2个link计数器,一个是i_link和i_count。

  i_count是当前进程打开文件的引用计数,i_link是文件链接的数量,可以把i_count理解为内存中文件的计数器,而i_link是磁盘中的计数器。对于rm命令来说实际就是设置磁盘中文件的i_link计数为0。如果一个文件被进程所使用,而用户又执行了rm命令把文件删除掉了,此时程序还能正常执行,依旧能从文件中读取正确的数据,这是因为rm命令只是把i_link设置为 0(是将文件到inode的关联断开,并没有删除掉inode与磁盘中的block数据块,此时停止进程,被删除的数据可以找回来,如果进程正在写入数据,那么磁盘的block块的数据会被进程写入的数据覆盖掉,原先的数据就恢复不了了)。

  而进程仍然在引用该文件i_count = 1,执行rm命令系统并不会真正的删除该文件,如果要删除该文件必须让进程解除对该文件的引用计数,也就是把进程干掉,这样文件才会被真正的删除掉。

  即便如此,文件真的被删除了吗?前面我们说过文件的数据是存储在磁盘上block块中,当我们要查找文件当中的数据时并不是直接找到磁盘上的block块,因为磁盘上的block块实在是太多了,你怎么就知道你的数据存储在哪个block块中?

  假设你一不小心把非常重要的数据删除掉了,这将意味着你的数据就永远也找不回来了,从而造成无法挽回的损失了,由此可见数据的重要性,因此操作系统不会轻易把数据从磁盘中真正的删除掉。

  看到这里,相信你已经明白了,实际上你所谓的右键删除操作只是把文件的inode索引号与磁盘中的block的关联断开了而已,但文件的数据并没有真正的被删除掉。如果你想真的删除数据的话,要么把磁盘格式化,要么把原先的数据删除掉,然后写入新的数据覆盖掉,当然,你也可以选择格式化和数据覆盖双重保险,这个时候你的数据想要恢复基本上是非常困难的,即便可以顶多只能恢复一部分数据了吧。

  如果你真的一不小心删除了很重要的数据的话,这个时候赶紧恢复数据,其他的任何多余的操作尽量不要做,这样在数据恢复过程中才能尽量减少数据丢失。

5. myunlink2.c程序

#include 
#include 
#include 
#include 
#include 
 /*
 unlink函数是删除一个dentry
 */
int main(void){
 int fd;
 char *p = "test of unlink\n";
 char *p2 = "after write something.\n";
 //当进程打开temp.txt文件时,引用计数会+1
 fd = open("temp.txt", O_RDWR|O_CREAT|O_TRUNC, 0644);
 if(fd <0){
 perror("open temp error");
 exit(1);
 }
 //具备了被释放的条件
 int ret = unlink("temp.txt"); 
 if(ret <0){
 perror("unlink error");
 exit(1);
 }
 //向temp.txt文件写入第一个字符串,通过返回值判断写操作是否成功
 ret = write(fd, p, strlen(p));
 if (ret == -1) {
 perror("-----write error");
 }
 printf("hi! I'm printf\n");
 //向temp.txt文件写入第二个字符串,通过返回值判断写操作是否成功
 ret = write(fd, p2, strlen(p2));
 if (ret == -1) {
 perror("-----write error");
 }
 printf("Enter anykey continue\n");
getchar();
 //当close关闭fd的时候,进程对文件的引用计数就会-1,断开进程与文件的关联关系
 close(fd);
 return 0;
}

程序运行结果:

这里写图片描述

&#8195;&#8195;程序的运行结果和我们所预料的一样,当程序运行的时候,调用open函数创建并打开了temp.txt文件,此时进程对temp文件的引用计数i_count会加1,同时temp文件本身也会有一个i_link链接计数也会加1。

&#8195;&#8195;当调用了unlink函数删除temp文件时,只是把i_link链接计数减1,而进程的i_count计数还是1,并没有断开与temp文件的关联关系,因此进程可以调用write函数往temp文件里面写数据,自然也就能成功了。当程序运行结束后,调用close关闭对temp文件的引用,此时temp文件就会被操作系统删除掉。

6. 总结

&#8195;&#8195;在不了解文件系统原理的情况下,通常我们会认为数据已经删除掉,其实不然,磁盘上的文件数据还在,只是把dentry目录和磁盘上的数据的联系断开,我们找不到数据肯定会认为删掉了,但是只要我们想办法让数据和dentry目录之间重新建立连接,就可以让删除的数据恢复。

&#8195;&#8195;因此我们删除文件,从某种意义上说,只是让文件具备了被释放的条件,至于什么时候释放这取决于操作系统。

&#8195;&#8195;对于unlink函数来说,清除文件时,如果文件的硬链接数到0了,没有dentry对应,但该文件仍不会马上被释放。要等到所有打开该文件的进程关闭该文件,系统才会挑时间将该文件释放掉。

7. 不要随便使用rm命令

&#8195;&#8195;相信看到这里,你应该知道了,数据对于计算机的重要性了,因为一旦某些至关重要的数据删除了,那就真的永远没了,这也是操作系统为什么不直接将数据从磁盘中删除的原因。但也不要因为这样,你就可以肆无忌惮的使用rm命令了,因为有时候数据删除了,并不能百分百的恢复回来。

总结

以上所述是小编给大家介绍的Linux unlink函数和删除文件的操作方法,希望对大家有所帮助,也非常感谢大家对网站的支持!


推荐阅读
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文介绍了使用CentOS7.0 U盘刻录工具进行安装的详细步骤,包括使用USBWriter工具刻录ISO文件到USB驱动器、格式化USB磁盘、设置启动顺序等。通过本文的指导,用户可以轻松地使用U盘安装CentOS7.0操作系统。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文主要讨论了在xps15上安装双系统win10和MacOS后,win10无法正常更新的问题。分析了可能的引导问题,并提供了解决方法。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 树莓派Linux基础(一):查看文件系统的命令行操作
    本文介绍了在树莓派上通过SSH服务使用命令行查看文件系统的操作,包括cd命令用于变更目录、pwd命令用于显示当前目录位置、ls命令用于显示文件和目录列表。详细讲解了这些命令的使用方法和注意事项。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
author-avatar
许更剑_725
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有