热门标签 | 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。



推荐阅读
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 原文地址http://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/最开始时 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了在实现了System.Collections.Generic.IDictionary接口的泛型字典类中如何使用foreach循环来枚举字典中的键值对。同时还讨论了非泛型字典类和泛型字典类在foreach循环中使用的不同类型,以及使用KeyValuePair类型在foreach循环中枚举泛型字典类的优势。阅读本文可以帮助您更好地理解泛型字典类的使用和性能优化。 ... [详细]
  • c语言基础编写,c语言 基础
    本文目录一览:1、C语言如何编写?2、如何编写 ... [详细]
  • 第四讲ApacheLAMP服务器基本配置Apache的编译安装从Apache的官方网站下载源码包:http:httpd.apache.orgdownload.cgi今 ... [详细]
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社区 版权所有