从对我的质疑说起,谈谈Linux下的文件删除

特特本来就是个刚毕业的小菜,很多知识都是靠着大家的指点才慢慢学会的。之前在一篇"纯属虚构"的文章 (鹅厂后台开发工程师的工作日常) 提到使用 rm 命令删除一个近 100 G 的 log 文件。

很荣幸,这篇文章被一个大号转载了,获得了很不错的阅读量。但是,当我看到有大佬在公众号留言,"质疑" 我文章内容的正确性,甚至把我个人的水平上升到了鹅厂程序员的水平高低问题时,我真是战战兢兢、瑟瑟发抖。

咱也不敢说,咱也不敢问,只能默默地去补习相关的知识,于是有了这篇文章。

一、Linux 删除文件的原理

通过查阅资料知道,Linux 系统下的文件被分成文件元数据 (metadata)和用户数据 (user data) 两部分。

用户数据,亦即文件数据块 (data block),是保存文件真实内容的空间;而元数据则是保存如文件大小、创建时间、所有者等文件的附加属性。

在 Linux 中,文件的元数据保存在一个 inode 结构中,inode 号是文件的唯一标识,而文件名仅是为了方便人们的记忆和使用。当然文件名与 inode 之间会存在映射关系。

而 inode 结构中与本文提到的文件删除相关的两个重要参数分别是:i_nlink i_count。从 VFS 的 inode 结构体定义中可以看到其类型如下:

struct inode {...const struct inode_operations  *i_op;      // 索引节点操作unsigned long                  i_ino;      // 索引节点号atomic_t                       i_count;    // 引用计数器unsigned int                   i_nlink;    // 硬链接数目...
}

当某个进程使用了文件时,该文件的 i_count 值会增加;当创建文件的硬链接 (区别于软链接)时,该文件的 i_nlink 值会增加。

i_nlink i_count 均为 0 时,文件才会被真正删除 (这里的删除是指删除了文件名到 inode  之间的链接关系,而文件的内容仍然完好无损地保存在磁盘中。如果此时关闭机器,阻止任何新的写磁盘操作,那么被删除的文件理论上也是可以恢复的)。

而执行删除命令 rm 时,本质上只是减少了 (或置0) 该文件的磁盘引用计数 i_nlink

换言之,如果被执行 rm 命令的文件正在被其他进程所引用,那么此时该文件对应的 i_count 将不为0,即便执行了 rm 操作,该文件并没有真正被删除,占用的磁盘空间也未被释放。

因此,上面截图中的评论是正确的,仅仅通过 rm 命令确实无法使用被进程打开的文件所占用的磁盘空间。

PS:为啥小特特在工作中可以直接通过 rm 删除和释放被进程使用的 log 文件呢?其实是因为通过脚本删除文件时会触发进程 reload 的逻辑,进程执行 reload 时会重新打开 log 文件 (当然会先关闭)。

二、Linux 删除大文件的几个简单方法

那么,Linux 下删除一个大文件的正确方式是什么呢?(假设待删除的大文件名为 access.log)

个人觉得最简单的方式是执行命令 > access.log。通过重定向 null 到待删除的文件可以让该文件瞬间成为空白,有效地释放磁盘空间。

另外,cat /dev/null > access.log 命令也是一个不错的选择。/dev/null 是一个特殊的文件,它可以清空送到它这里来的所有输入,而它的输出则可被视为一个空文件。

echo -n "" > access.log 也是常用的一个命令。需要注意的是,别忘了加上 -n 选项 (否则 access.log 文件中会出现一个空白行)。

当然,还可以通过 truncate 命令将待删除的文件大小缩小为0,但是我平时用得很少。

三、Linux 进程打开的文件信息

再延伸下:

在 Linux 系统下,当进程打开一个文件后,内核会为该进程在 /proc/ 目录下建立一个以该进程 pid 为名的文件夹来保存该进程的相关信息。而 /proc/pid/fd/  文件夹保存的就是该进程打开的所有文件的文件描述符 (file descriptor, fd)。

除了打开的本地文件,进程建立的 socket 链接也算是一个 fd。

一个进程打开的文件数量是有限的,执行 cat /proc/pid/limits | grep "Max open files" 命令可以查看进程号为 pid 的进程允许打开的最大文件个数。

当在 Linux 下调用 open 函数返回了系统错误码 24 时 (对应的系统错误描述是:"Too many open files"),则表示当前进程打开的文件数量超过了系统设置的上限。

如果你的程序遇到了这个错误,按我的经验来看,一般是出现句柄泄漏了 (可能是文件未正常关闭、socket 链接未正常断开等),这时候就需要你耐心地 debug 啦

四、如何高效清空包含大量小文件的目录

再再延伸下:

Linux 下怎么快速地删除包含大量小文件的目录?

直接通过 rm -rf ./* 命令容易导致系统 I/O陡增。我一般使用的方法是利用 rsync 命令同步目录的机制,通过新建一个空目录,再将待删除的目录与新建的空目录进行同步,从而达到清空目录的目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310595.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zookeeper实践与应用--分布式锁实现

分布式锁 分布式锁是控制分布式系统之间同步访问资源的一种方式,如果不同系统是同一个系统的不同主机之间共享一个或一组资源,那么访问这些资源的时候,往往需要通过一些呼哧手段来防止彼此之间的干扰保证统一性,因此需要分布式锁…

关于 Blazor Server Side 的一些杂项, 感想

在2016年, 本人就开始了一个内部项目, 其特点就是用C#构建DOM树, 然后把DOM同步到浏览器中显示. 并且在一些小工程中使用.3年下来, 效果很不错, 但因为是使用C#来构建控件树, 在没有特定语法的情况下, 代码风格不是那么好.典型的风格大概是这样的:这个模式挺好的, 有点嫌弃C#代…

重现江湖!大数据高并发——架构师秘籍

大数据高并发的话题屡见不鲜,各种应对的方式方法也四处可见。然而笔试面试中一问就懵,简直是高薪拦路虎。为什么呢?究其原因,还是思路不清晰,缺乏实操,所以一问就倒。作为专注.Net领域十几年的老司机&#…

[剑指offer]面试题4:替换空格

面试题4:替换空格 题目:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We are happy.”,则输出“We%20are%20happy.”。 ❖ 时间复杂度为O(n2)的解法,不足以拿到Offer…

Zookeepe实践与应用--分布队列

分布式队列 接触到不少分布式队列的产品,比如,ActiveMq,RocketMQ,kafka等消息中间价,现在我们看看Zookeeper实现的分布式队列。分布式队列简单讲就可以分两个部分,一种是先进先出,另外一种是等…

ASP.NET Core+Quartz.Net实现web定时任务

点击蓝色“Dotnet Plus”关注我哟加个“星标”,每天清晨 07:25,干货推送!作为一枚后端程序狗,项目实践常遇到定时任务的工作,最容易想到的的思路就是利用Windows计划任务/wndows service程序/Crontab程序等主机方法在主…

Redis基础数据结构内部实现简单介绍

5种基础数据结构 Redis有5种基础数据结构,分别是:String(字符串),list(列表),hash(字典),set(集合),zset&…

[剑指offer]面试题7:用两个栈实现队列

面试题7:用两个栈实现队列 题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。 用两个栈模拟一个队列的操作: 代码如下: #include …

ASP.NET CORE WEBAPI文件下载

最近要使用ASP.NET CORE WEBAPI用来下载文件,使用的.NET CORE 3.1。考虑如下场景:文件是程序生成的。文件应该能兼容各种格式。浏览器可以感知进行下载。准备经过简单的调研,得到以下结论。ASP.NET CORE 提供FileResult这种类型的ActionResul…

Redis高级数据结构原理解析-bitmap,hyperloglog

Redis 位图 开发过程中,我们可能遇到这种场景记录用户的打卡情况,签到情况,这些场景只有两种结果,有或者没有,加入记录的数据量比较大,比如用一年的数据,如果用Redis中普通key/value&#xff0…

[剑指offer]面试题8:旋转数组的最小数字

面试题8:旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数…

.NET Core + Kubernetes:快速体验

Kubernetes[1] 是目前非常主流的容器编排工具,在应用创建、应用部署、应用扩容、应用更新等方面都非常的方便,而且在应用故障时,也可以快速自愈。所以基于微服务架构下的产品,了解 Kubernetes 的使用是非常必要的,我猜…

[剑指offer]面试题9:斐波那契数列

面试题9:斐波那契数列 题目一:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列的定义如下: ❖ 效率很低的解法,挑剔的面试官不会喜欢 代码如下: long long fib(…

Redis分布式锁奥义

分布式锁 分布式系统进行逻辑处理的时候,经常会遇到并发问题,例如直播场景中,用户需要连麦主播,当多个用户在同一个时刻一起连麦时候,应该保证只有一个用户能连麦成功,我们改怎么保证这种业务场景下保证数…

.NET Core + Kubernetes:Pod

在 .NET Core Kubernetes:快速体验 文章中,已经实现将一个 .NET Core API 服务部署在 Kubernetes 集群中,接下来将逐步了解 Kubernetes 中各核心模块。首先当然是 Pod,我相信 Pod 是在接触 Kubernetes 时听到较多的一个词语&…

LBS解决方案

LBS解决方案 LBS(基于地理位置的服务)服务是现在移动互联网中比较常用的功能,例如外卖中我附近的店铺,通常是以客户位置坐标为中心,查询一定范围内的店铺信息,按照距离由近及原进行倒叙排序 方案一&#…

长沙IT技术圈百万年薪大佬?是否存在?

作者:邹溪源,长沙资深互联网从业者,架构师社区特邀嘉宾!01引子不知不觉,IT技术圈开始流传起“百万年薪”的故事,有人问我,长沙有百万大佬么?其实我也不知道。02背景长沙自古以来就是…

网络编程-网络分层的意义

网络 我们生活在一个网络无处不在的一个虚拟世界中,网络中的每一个设备都是一个节点。大多是我们的计算机,但是他还可以连接其他设备,例如打印机,路由器,网关,你的手机,智能家居等。我们可以使…

网络编程-TCP/IP协议栈-IP协议

协议 协议就是约定的一种规则&#xff0c;例如扑克游戏中约定好的各种规则&#xff0c;2<3<4<5<…等&#xff0c;以此作为游戏规则。当所有人都遵循这个规则&#xff0c;那么久可以不需要任何多余的交流就可以进行游戏&#xff0c;这个方式形成的约定就是一种协议…

.NET项目升级手记:可为空引用

c# 8引入了新特性&#xff1a;“可为空引用”&#xff08;详情&#xff09;&#xff0c;这个功能个人觉得挺好的&#xff0c;能够非常明确的表现程序设计者的意图&#xff0c;编译器能够进行检查&#xff0c;尽最大可能减小NullReferenceException错误。如果是新项目&#xff0…