热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux:详解基础IO(重定向、静态库和动态库、ext2文件系统、软硬连接)(二)

目录1.重定向1.1前言1.2重定向的命令符号1.3重定向的原理1.4重定向的代码实现2.静态库和动态库2.1动态库2.1.1分类2.1.2动态库的编译生成2.1.3动态库的使用&

目录

  • 1.重定向
    • 1.1 前言
    • 1.2 重定向的命令符号
    • 1.3 重定向的原理
    • 1.4 重定向的代码实现
  • 2.静态库和动态库
    • 2.1 动态库
      • 2.1.1 分类
      • 2.1.2 动态库的编译生成
      • 2.1.3 动态库的使用(场景)
      • 2.1.4 动态库配合环境变量的使用
    • 2.2 静态库
      • 2.2.1 分类
      • 2.2.2 静态库的编译生成
      • 2.2.3 静态库的使用
  • 3. ext2文件系统
    • 3.1 存储数据的逻辑
    • 3.2 获取数据的逻辑
    • 3.3 相关命令语句
  • 4. 软硬链接
    • 4.1 软链接
    • 4.2 硬链接




1.重定向

1.1 前言

重定向是什么呢?举个例子来看一下

我们首先创建一个不包含任何内容的文件1.txt
在这里插入图片描述
然后我们将ls -l的命令重定向到1.txt
在这里插入图片描述
查看1.txt中的内容
在这里插入图片描述


1.2 重定向的命令符号


  • >:清空重定向,将文件清空之后,再进行重定向
  • >>:追加重定向,直接将重定向的内容放在该文件的尾部

相当于C语言fopen函数中的 w、w+ 属性。

1.3 重定向的原理

首先,我们来看一下Linux中一个程序所对应的默认的文件输出信息,在/proc/[PID]/fd路径下查看

在这里插入图片描述
再看看/dev/pts/0里到底是什么
在这里插入图片描述

那么,重定向的原理是什么呢?拿前言中的例子来说,ls命令本来是将结果输出到屏幕上,而我们使用重定向将其本要输出到屏幕上的内容转而输出到了1.txt文件中,其本质就是修改了ls命令的标准输出(fd_adday[1])的指向。
用图来解释一下就是:

①初始的时候
在这里插入图片描述
②当使用重定向后,将fd_array[1]的指向重新设置为fd_array[3]的指向的结构体
在这里插入图片描述
此时,当使用 ls 命令时,它的内容就不会输出再屏幕上,而是会输出到1.txt文件中

总结一下重定向的原理是:将fd_array数组中的元素struct file * 指针的指向关系进行改变,改变成为其他struct file 结构体的地址

1.4 重定向的代码实现

首先来看一个重定向的函数

int dup2(int oldfd, int newfd);

它的参数,如字面意思一样,给定两个文件描述符即可,dup2函数中也有对应的特性。我们接下来一一的进行探讨。
查看dup2函数的描述可得:

特性①:
在这里插入图片描述
解释:dup2的newfd是拷贝于oldfd的,也就是说,当重定向之后,oldfd的指向还是存在的,并不会随着dup2的调用而消失。举个例子来说就是dup2(0,3),相当于将 fd[3] 变为标准输入流,但是原来的 fd[0] ,还是存在的,并不会关闭。

特性②:
在这里插入图片描述
解释:如果必要,则在使用dup2进行重定向的时候,会先关闭newfd,(这里的必要是指:oldfd是正常的文件描述符),但是还要注意以下几点:

  • note1:
    在这里插入图片描述
    解释:若oldfd不是一个有效的文件描述符,则不关闭newfd,重定向失败
  • note2:
    在这里插入图片描述
    解释:若oldfd是一个有效的文件描述符,并且oldfd和newfd拥有相同的文件描述符数值,那么dup2函数什么都不干,且返回newfd

返回值:若重定向成功,则返回newfd,若失败,则返回-1。

用代码实现重定向

在实现代码之前,首先先明确该代码应该实现的功能:首先获得当前目录下一个文件的文件描述符fd,如果不存在则创建。然后调用dup2函数将标准输出的文件描述符重定向到fd,标准输出为newfd,fd为oldfd,然后通过printf函数进行打印,查看其现象。

代码如下:

代码1:

#include
#include
#include
#include int main()
{int fd &#61; open("./1.txt",O_RDWR | O_CREAT,0664);if(fd < 0){perror("open");exit(1);}//将标准输出重定向至当前文件&#xff0c;表示当进行输出的时候&#xff0c;会将内容打印到1.txt中&#xff0c;而不是打印在屏幕上//将oldfd拷贝于newfddup2(fd,1);while(1){//重复打印10次到1.txt中printf("It&#39;s test to redirect!");sleep(1);}return 0;
}

结果探讨&#xff1a;由于是while(1)死循环&#xff0c;那么在重定向之后&#xff0c;在执行printf时&#xff0c;会不停的往1.txt文件中输出 It’s test to redirect !&#xff0c;那么结果是否是如此呢&#xff0c;我们来运行一下&#xff1a;

为了能看到程序运行的结果&#xff0c;我们使用tail -f 1.txt的语句来实时查看1.txt文件当中的内容
在这里插入图片描述
使用tail -f 1.txt
在这里插入图片描述
我们发现好像并没有写入到1.txt中&#xff0c;为什么呢&#xff1f;
在这里插入图片描述
查看一下文件描述符&#xff0c;发现重定向已经成功了&#xff0c;但是为什么没有打印到1.txt呢&#xff1f;
然后过了一会&#xff0c;我们再使用tail -f 1.txt查看1.txt内容&#xff0c;发现已经写到文件中了
在这里插入图片描述

那这到底为什么会这样呢&#xff1f;为什么一开始并不会向1.txt中写入文件&#xff0c;而是过一会才写入文件中呢&#xff1f;

解答&#xff1a;C库函数写入文件时是全缓冲的&#xff0c;而在写入显示器时是行缓冲的。

  • 当写入文件时&#xff0c;’\n’就不管用了&#xff0c;需要搭配fflush() 函数来强制刷新缓存区&#xff08;或者等待程序结束时的强制刷新&#xff09;
  • ‘\n’ &#xff0c;只对行缓冲区有用

因此&#xff0c;解决该问题有两种办法

  • 规定循环次数&#xff08;循环结束&#xff0c;程序结束&#xff0c;会自动刷新缓冲区&#xff09;
  • 使用fflush函数强制刷新缓冲区

代码改进&#xff1a;

#include
#include
#include
#include int main()
{int fd &#61; open("./1.txt",O_RDWR | O_CREAT,0664);if(fd < 0){perror("open");exit(1);}//将标准输出重定向至当前文件&#xff0c;表示当进行输出的时候&#xff0c;会将内容打印到1.txt中&#xff0c;而不是打印在屏幕上//将oldfd拷贝于newfddup2(fd,1);int count &#61; 10;while(count--){//重复打印10次到1.txt中printf("It&#39;s test to redirect!\n");//fflush()sleep();}return 0;
}

这次我们再来看一下结果

在这里插入图片描述
发现可以输出是和我们的猜想一致&#xff0c;很完美&#xff01;&#xff01;


2.静态库和动态库

2.1 动态库


2.1.1 分类


  • Windows操作系统下&#xff1a;若文件的后缀为.dll&#xff0c;则表明该文件为动态库
  • Linux操作系统下&#xff1a;若文件的后缀为.so&#xff0c;前缀为lib&#xff0c;则表明该文件为动态库

2.1.2 动态库的编译生成

命令&#xff1a; gcc/g&#43;&#43;

必选命令行参数&#xff1a;

  • -shared&#xff1a;生成的动态库
  • -fPIC&#xff1a;生成与位置无关的代码&#xff08;该参数会计算出程序的相对位置&#xff09;

命令范式&#xff1a;

gcc/g&#43;&#43; [soure code] -shared -fPIC -o lib[动态库名称].so

举个例子&#xff1a;

在这里插入图片描述

注意&#xff1a;生成的动态库中不能包含main函数&#xff01;&#xff01;&#xff01;

使用动态库的原因&#xff1a;

防止源码泄漏&#xff0c;因为动态库是编译.c文件生成的二进制文件&#xff0c;因此当要发布产品时&#xff0c;只需要将动态库和其对应的.h文件发布即可&#xff0c;这就实现了我能知道这个代码各个函数能实现什么功能&#xff0c;但是不知道其内部的具体实现&#xff0c;封装性极强&#xff0c;可以极大的防止源码泄漏。


2.1.3 动态库的使用&#xff08;场景&#xff09;


本质上是想要使用动态库产生一个可执行的程序

参数&#xff1a;

  • - L &#43; [动态库所在路径]
  • -l &#43; [动态库名称](注意&#xff1a;这里的动态库名称是指&#xff0c;去掉前缀和后缀之后的名称)

命令范式&#xff1a;

gcc/g&#43;&#43; [source code] -o [可执行程序] -L [动态库所在路径] -l[动态库的名称]

举个例子&#xff1a;

在这里插入图片描述

ldd &#43; [可执行程序]&#xff1a;可以查看当前可执行程序所有依赖的动态库的名称

在这里插入图片描述

该命令很是重要&#xff0c;在以后实战中可能会经常遇到

2.1.4 动态库配合环境变量的使用

若是我不小心将当前目录下的动态库给移走了&#xff0c;那么此时程序还能正常运行吗&#xff1f;

在这里插入图片描述

那么问题来了&#xff1a;如何让可执行程序能够找到依赖的动态库在哪里

解决方案&#xff1a;配合环境变量LD_LIBRARY_PATH进行使用

  • LD_LIBRARY_PATH&#xff1a;是动态库的搜索的环境变量
  • PATH&#xff1a;是可执行程序的搜索的环境变量

将动态库所在位置&#xff0c;放入系统的环境变量中即可解决该问题。

在这里插入图片描述


2.2 静态库


2.2.1 分类


  • Windows操作系统下&#xff1a;若文件的后缀为.lib&#xff0c;则表明该文件为静态库
  • Linux操作系统下&#xff1a;若文件的后缀为.a&#xff0c;前缀为lib&#xff0c;则表明该文件为静态库

2.2.2 静态库的编译生成

命令范式&#xff1a;

ar -rc lib[静态库名称].a [依赖的文件]

这里依赖的文件是指整个汇编过程完成之后的文件&#xff0c;即.o文件

步骤&#xff1a;

  • 先将要编译静态库的代码&#xff0c;编译到汇编阶段
  • 使用ar -rc生成静态库&#xff08;二进制代码文件&#xff09;

举个例子&#xff1a;

在这里插入图片描述


2.2.3 静态库的使用

命令范式&#xff1a;

gcc [soure code] -o [可执行程序] -L [静态库路径] -l[静态库名称]

这里的静态库名称和动态库一样&#xff0c;都是去掉前缀和后缀之后的名称

注&#xff1a;若可执行程序依赖静态库编译成功的&#xff0c;会将静态库的内容直接打包到可执行程序中。并且ldd命令是查看不到其依赖关系的。

举个例子&#xff1a;

在这里插入图片描述

扩展&#xff1a;

  • 一个程序依赖动态库或者依赖静态库生成可执行程序时&#xff0c;动态库或静态库是不会干扰到链接方式的&#xff08;此处的链接方式指得是静态链接和动态链接&#xff09;
  • 在编译可执行程序时&#xff0c;使用gcc/g&#43;&#43;编译时&#xff0c;默认不增加命令行参数-static&#xff0c;则表明该链接为动态链接&#xff0c;反之&#xff0c;则为静态链接
  • 静态链接就是在编译时&#xff0c;主动加上-static参数的程序&#xff0c;这时候用ldd命令查看会什么也查不到&#xff0c;因为他会将所有依赖的文件全部封装到可执行程序中去&#xff0c;相对于的可执行程序会异常的大

在这里插入图片描述
再看看它的文件大小
在这里插入图片描述


碎片知识&#xff1a;动态库是不能用静态链接的生成可执行程序&#xff08;静态库是可以的&#xff09;&#xff0c;但是这种情况只是指自己编译的动态库是不行的。而操作系统的动态库是可以静态链接的

3. ext2文件系统

众所周知&#xff0c;系统的磁盘是分为好几个区的&#xff0c;如C区、D区等等&#xff0c;每个区或许都有它对应的文件系统&#xff0c;本节我们就着重讲讲ext2文件系统。

在这里插入图片描述

Linux ext2文件系统&#xff0c;上图为磁盘文件系统图&#xff08;内核内存映像肯定有所不同&#xff09;&#xff0c;磁盘是典型的块设备&#xff0c;硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的&#xff0c;并且不可以更改。上图中启动块&#xff08;Boot Block&#xff09;的大小是确定的。

  • Block Group&#xff1a;ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。相当于政府管理各区的例子
  • 超级块&#xff08;Super Block&#xff09;&#xff1a;存放文件系统本身的结构信息。记录的信息主要有&#xff1a;bolck 和 inode的总量&#xff0c;未使用的block和inode的数量&#xff0c;一个block和inode的大小&#xff0c;最近一次挂载的时间&#xff0c;最近一次写入数据的时间&#xff0c;最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏&#xff0c;可以说整个文件系统结构就被破坏了。
  • GDT&#xff0c;Group Descriptor Table&#xff1a;块组描述符&#xff0c;描述块组属性信息。
  • Block Bitmap&#xff1a;块的位图&#xff0c;描述每一个块的使用情况&#xff0c;若使用则比特位为1&#xff0c;反之为0。
  • inode Bitmap&#xff1a;它描述了inode结点的使用情况&#xff0c;即描述了inode table中&#xff0c;哪一个inode结点被使用&#xff0c;哪一个inode结点没有被使用
  • inode Table&#xff1a;里面存放了inode的结点

inode结点&#xff1a; 用来描述文件存储的信息以及对应的文件元信息。

  • Data blocks&#xff1a;反映了块的使用情况&#xff0c;即Block Bitmap中保存的结果是根据Data blocks的存储信息得来的。


3.1 存储数据的逻辑

① 从block Bitmap当中查找到空闲的Data block块&#xff0c;将文件分成不同的块存储在不同的block中。

② 从inode Bitmap中查找空闲的inode结点&#xff0c;将文件信息保存在inode中&#xff0c;其中文件信息包括文件在哪些block块中存储&#xff0c;位均名称,文件大小,文件权限,文件访问时间,文件修改时间,文件修改属性时间,文件拥有者,文件所属组。

③将文件的名称和inode结点号&#xff0c;作为目录的目录项保存下来。

3.2 获取数据的逻辑

①通过目录项当中的文件名称找到对应的inode结点号。

②通过inode节点号&#xff0c;找到对应的inode结点&#xff0c;通过inode结点找到文件的元信息。

③通过文件元信息&#xff0c;找到文件存储的block块&#xff0c;将文件内容组合起来。

④展示给用户&#xff0c;文件的元信息以及文件的内容

3.3 相关命令语句

df -h命令可以查看磁盘的情况&#xff08;分区、大小&#xff09;

如下&#xff1a;在这里插入图片描述

ll -i可以查看inode的结点号

在这里插入图片描述

stat [文件名称]:查看文件详细信息&#xff08;文件的元信息&#xff09;

在这里插入图片描述


4. 软硬链接

4.1 软链接

概念&#xff1a;

软链接就是给文件创建了一个快捷 方式

创建&#xff1a;

使用ln -s [原文件] [创出的软链接名称]命令
在这里插入图片描述

软链接探讨

① 对比inode结点号

在这里插入图片描述
发现软链接的inode号和源文件的inode号是不一样的&#xff0c;但是它们所指向的block是一样的

② 当删除源文件时&#xff0c;软链接的状态

在这里插入图片描述
再重新创建一个test.c的文件&#xff0c;查看其状态
在这里插入图片描述


发现软链接又重新指向test.c文件&#xff0c;但是其中的内容发生了改变&#xff0c;不在是以前的test.c文件。

总结&#xff1a;修改源文件会影响软链接文件&#xff0c;修改软链接文件也会影响源文件&#xff0c;因此&#xff0c;在删除源文件的时候&#xff0c;一定要把软链接文件也给删除掉


4.2 硬链接

概念&#xff1a;

硬链接相当于文件的一个备份&#xff08;拷贝&#xff09;

创建&#xff1a;

使用ln [源文件] [硬连接文件]命令
在这里插入图片描述
硬连接具有和源文件相同的inode结点号&#xff0c;并且是一个普通的文件&#xff0c;生成硬链接后&#xff0c;对应的硬链接文件数也变为 2。



推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了在Windows系统上使用C语言命令行参数启动程序并传递参数的方法,包括接收参数程序的代码和bat文件的编写方法,同时给出了程序运行的结果。 ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • 本文介绍了OkHttp3的基本使用和特性,包括支持HTTP/2、连接池、GZIP压缩、缓存等功能。同时还提到了OkHttp3的适用平台和源码阅读计划。文章还介绍了OkHttp3的请求/响应API的设计和使用方式,包括阻塞式的同步请求和带回调的异步请求。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • C语言自带的快排和二分查找
    Author🚹:CofCaiEmail✉️:cai.dongjunnexuslink.cnQQ😙:1664866311personalPage&#x ... [详细]
author-avatar
手机用户2602918231
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有