当前位置: 首页 > news >正文

从对我的质疑说起,谈谈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.taodudu.cc/news/show-911440.html

相关文章:

  • Liunx_DNS域名解析服务
  • 判断一个类中的属性是否可写
  • IT行业现状与未来趋势分析
  • Ubuntu下C++编程总结AllInOne
  • docker-compose使用
  • ssm123基于java web的网上书城系统的设计与实现+vue
  • 关于 Blazor Server Side 的一些杂项, 感想
  • 重现江湖!大数据高并发——架构师秘籍
  • ASP.NET Core+Quartz.Net实现web定时任务
  • ASP.NET CORE WEBAPI文件下载
  • .NET Core + Kubernetes:快速体验
  • 海底捞涨价,有错吗?
  • .NET Core + Kubernetes:Pod
  • .NET项目升级手记:可为空引用
  • .NET与鲲鹏共展翅,昇腾九万里(一)
  • 十问十答 Ms-PL 许可证
  • 从案例角度解析建模平台动态规则引擎
  • 想基于K8s按需扩展应用程序,可从这几方面入手
  • EntityFramework Core 3.x上下文构造函数可以注入实例呢?
  • IO 模型知多少
  • 让 .NET 轻松构建中间件模式代码
  • 从编码层面对比java和c#
  • 红帽借“订阅”模式成开源一哥,首创者升任总裁
  • C#两大知名Redis客户端连接哨兵集群的姿势
  • dotNET Core 3.X 请求处理管道和中间件的理解
  • 了解.NET中的垃圾回收
  • 数字化演化历史
  • 如何查找,修复和避免C#.NET中内存泄漏的8个最佳实践
  • ASP.NET Core技术研究-探秘依赖注入框架
  • 从项目到产品: 软件时代需要价值流架构师 | IDCF
  • 推荐一个集录屏、截图、音频于一体的软件给大家
  • WebAssembly增加Go语言绑定
  • .NET中的内存管理
  • .Net微服务实战之技术架构分层篇
  • .NET 下基于动态代理的 AOP 框架实现揭秘
  • Blazor WebAssembly 3.2.0 Preview 4 如期发布