跟我学C++中级篇——Linux中文件和链接及重定向

一、Linux中的文件

在前面学习网络句柄等知识点时,提到过,在Linux中,一切皆文件。所以文件可以从广义和狭义两个层次来描述。狭义的文件,其实是就是大家在硬盘中看到的各种文件,包括什么mp3,mp4等音视频文件,.h,.cpp等C++源码文件以及最常见的txt文本文件等等。也就是说,磁盘中存在的存储的资源都可以称为文件。

而从广义上理解,则一切都是文件,如网络通信的句柄、事件的句柄、U盘以及键盘等外设、设备等等也都是文件。这样的好处在于从抽象层次上,统一了所有的管理和操作行为。这对于内核的开发变得更方便一致。

二、链接

在Linux中文件的链接又分为软链接和硬链接。软连接指通过ln -s创建的文件的链接,它类似于Windows上的快捷方式。如下命令:

复制代码
ln -s sourceFileName linkSoftFileName  #create
unlink linFileName                #remove

它有点类似于指针。单纯的删除软链接文件,并不会影响源文件本身;但是如果删除源文件,则软链接文件变得不可用。软链接是有独立的inode的,其内部存储的是源文件的地址。

硬链接是指直接使用ln创建的文件链接(和软链接区别在于是否有-s),如下命令:

复制代码
ln sourceFileName linkhardFileName

硬链接类似于智能指针,通过引用计数器控制硬链接的数量,即在每个描述源文件的inode中生成一个文件映射即硬链接文件的映射,而没有真正的生成一个文件。所以单纯删除硬链接的源文件,是无法删除源文件的,只是删除了一个文件入口而已。

一般在源码中实现软硬链接可以使用库接口symlink(软链接)和link(硬链接)来实现。

三、重定向

在查看日志或者一些查询导出时,大家可能经常使用类似下面的命令:

复制代码
cat top.log|grep abc >file.txt #输出重定向
cat < top.log              #输入重定向

所谓重定向,其实就是将对文件句柄fd的操作目标改变(所谓重定向),也可以这样理解,就是将fd(指针)从原来指向的目标(内存地址)更改为指定的目标(新内存地址)。其具体的实现,一般来说可以先关闭原来的句柄再将新fd赋值即可。但为了方便在库中提供了一个dup2的接口函数,可以更方便的进行重定向实现。

需要提醒的是重定向命令有">"和">>"或"<"和"<<"两种,一种是单次重定向(即清除原有的内容只显示最新的);另外一种是追加重定向(可以不断追加更新内容)。

四、文件句柄的本质

无论是软硬链接还是重定向,本质都是对文件的管理和操作。而操作文件的本质是是对文件句柄的操作。而文件句柄fd即文件描述符在内核中被描述为files_struct:

c 复制代码
struct files_struct {
  /*
   * read mostly part
   */
	atomic_t count;
	bool resize_in_progress;
	wait_queue_head_t resize_wait;

	struct fdtable __rcu *fdt;
	struct fdtable fdtab;
  /*
   * written part on a separate cache line in SMP
   */
	spinlock_t file_lock ____cacheline_aligned_in_smp;
	unsigned int next_fd;
	unsigned long close_on_exec_init[1];
	unsigned long open_fds_init[1];
	unsigned long full_fds_bits_init[1];
	struct file __rcu * fd_array[NR_OPEN_DEFAULT];//重点
};

也就是通过fd_array来保存相关的文件描述符。而无论是开发者还是内核本身,想操作文件如open等,其实就是对这个数组的检索然后再进行的。而分配亦也是如此,找到第一个空的位置,然后再保存进去即可(一般来说,数组的前三个已经被标准的输入输出和错误占用)。

五、相关例程

下面给出一个基础的实现例程:

c 复制代码
#include <iostream>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

void redirect() {
  int fd = open("./test.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
  if (fd < 0) {
    perror("open");
    return;
  }

  // fd复制到1
  dup2(fd, 1);

  //重定向打印
  std::cout << "hello ,redirect!!!" << std::endl;

  close(fd);
}

int main() {
  // 创建软链接
  symlink("test_demo.txt", "soft.txt");
  // 创建硬链接
  link("test_demo.txt", "hard.txt");

  redirect();

  return 0;
}

代码很简单,如果有不明白的地方上机运行一下就明白了。

六、总结

学习一些Linux的基本知识点时,完全可以从开发的角度来看。特别是内核是开源的,有什么不明白的细节,打开源码搜索到相关的位置就一目了然了。再次引用侯先生的话"源码之前,了无秘密"!再掌握了相关的应用后,从编码的角度再造一次轮子,可以更加深刻的理解设计的目的和思想,提高开发者自身的认知水平和编程方式。与诸君共勉!

相关推荐
MC皮蛋侠客17 小时前
Google Test 单元测试指南
c++·单元测试·google test
2301_8090511417 小时前
Linux 网络编程 学习笔记
linux·网络·学习
坤昱17 小时前
cfs调度类深入解刨——最新内核细节分析2
linux·服务器·cfs·cfs调度·eevdf调度·eevdf·kernel 7.1
艾莉丝努力练剑17 小时前
【Linux:文件】Ext系列文件系统进阶
linux·运维·服务器·c++·文件系统·文件io·ext
海市公约17 小时前
Linux核心基础命令与权限管理实战指南
linux·运维·服务器·vim·权限管理·系统监控·命令行
eggcode18 小时前
【Qt学习】Linux(ARM架构)在线安装Qt6.x
linux·qt·学习·arm
wkd_00718 小时前
Ubuntu 22.04 Samba 连接故障排查记:从“用户名或密码错误”到 NTLM 版本不兼容
linux·运维·ubuntu
mixboot19 小时前
Linux 进程工作目录查看利器:pwdx 命令详解
linux·运维·服务器
basketball61619 小时前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++
旺仔来了20 小时前
不联网的Linux下部署python环境
linux·开发语言·python