Linux系统编程(三)—— 文件编程(1)目录和文件

3.1 目录和文件

  • 贯穿始终的例子:做一个类似 ls 命令的实现。如myls

1、命令

  • (1)一个命令的格式:cmd --长格式 -短格式 非选项的传参
    比如 ls --allls -a,这两个结果是一样的:
    在这里插入图片描述

  • (2)为什么短格式可以,还要存在长格式呢?

    可能两个单词的首字母什么的会相同。或者两个单词的缩写撞在了一起。

  • (3)如果要创建一个名字为 -a 的文件,应该如何做?

    在这里插入图片描述
    解决办法:
    1)touch -- -a 命令后面加上两个减号,表示当前的命令结束;

    在这里插入图片描述

    2)touch ./-a 将路径写上,就不会被认作命令参数了。

    在这里插入图片描述

    上述两种方法,对于删除 -a 这个文件也同样适用。

  • (3)注意:ls -lls -n的区别:前者显示用户ID ,后者显示用户NAME

    在这里插入图片描述

  • (4)/etc/passwd/etc/group文件

    1)/etc/passwd文件,用户名 :group名 :用户ID :groupID
    在这里插入图片描述
    2)/etc/group文件, 用户名:组名 :组号
    在这里插入图片描述

2、如何获取文件属性:stat (系统调用)

在这里插入图片描述

  • 注意:这三个函数的格式,在linux当中,很多函数的封装是沿用这样的规律的,很多命名规则都是这样的
    (1)stat : 通过名字做这件事
    (2)fstat : 通过文件描述符来做这件事情
    (3)lstat : lstat 和 stat 在参数和返回上都一样,但是他们在link的处理上是不同的
    (stat面对符号链接文件时获取的是所指向文件的属性;而 lstat 面对符号链接是获取的是符号链接文件属性)

  • stat 结构体长这样,包含文件的全部内容:

    在这里插入图片描述
    在这里插入图片描述

  • 同时stat 也是一个命令:用来显示一个文件的属性, 所以stat这个命令是用stat这个函数封装出来的。
    在这里插入图片描述

  • 例子: 显示一个文件的大小:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

static int flen(const char *fname) // static表示这个函数禁止外部扩展
{
    struct stat statres;
    if(stat(fname, &statres) < 0)
    {   
        perror("stat");
        exit(1);
    }   
    return statres.st_size;
}

int main(int argc, char **argv)
{
    if(argc < 2)
    {   
        fprintf(stderr, "Usage ... \n");
        exit(1);
    }   
    printf("%d \n", flen(argv[1]));
    exit(0);
}

运行结果:
在这里插入图片描述

  • 注意:
    实际上,windows中,一个文件的大小就是所占的磁盘的大小,但是在linux中,并不是这样的,一个文件所占的大小是由这个文件所占用的block大小和block数量决定的block是指一个文件所占用的块数, 永远指的是扇区数

3、空洞文件

我们做一个非常大的文件,但是占用磁盘空间很小,甚至不占用:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    int fd; 
    if(argc < 2)
    {   
        fprintf(stderr, "Usage ...\n");
        exit(-1);
    }   

    fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0600);
    if(fd < 0)
    {   
        perror("open");
        exit(-1);
    }
    
    // 5G, 将文件尾指针一下子扯过去
    lseek(fd, 5LL * 1024LL * 1024LL * 1024LL - 1LL, SEEK_SET);

	// 使用一次系统调用,如果没有这次系统调用,当前文件是不占用空间的
    write(fd, "", 1);              
    close(fd);
    exit(0);
}

运行这个文件,然后得到一个大文件,可以看到,虽然这个文件显示的是5G大小,但是它所占磁盘空间才8k, 很小很小。
在这里插入图片描述
然后cp 拷贝一下这个文件,你会发现拷贝以后的文件所占磁盘大小尾0, 为什么呢??

因为cp在拷贝的时候,会判断这个文件是否是空洞文件,如果中间有空字符,它会记住空字符的长度,但是不会存这个空字符,所以它拷贝以后的这个文件是0字节。

4、文件属性与访问权限问题

  • 当执行命令ll的时候,如下: (红框框中的内容是文件的权限信息):
    在这里插入图片描述

  • 文件的权限信息包括:(文件的权限信息存在于 st_mode 当中,st_mode的存放形式是以位图的形式存放的, 是16位的一个整型数。

  • 为什么是16位?
    (1)基本位是9位(owner读写执行权限 (421)+ group读写执行权限(421)+other读写执行权限(421));
    (2)加另外3位(粘住位,set groupID位,set userID位);
    (3)文件类型是7类,用二进制表示使用3位;

    =>加一起是15位,但是没有15位的整型数,所以是使用16位的整型数表示的。

  • st_mode存了两种类型:

    (1)文件类型(分为dcb-lsp七种文件类型)
    d——目录;
    c——字符设备文件;
    b——块设备文件;
    -——常规文件;
    l——符号链接文件;
    s——网络套接字socket文件;
    p——管道文件

    (2)文件权限(当前用户owner, 当前组用户group, 其他用户other)

  • 注意: st_mode是一个16位的位图,用于表示文件类型、文件访问权限、特殊权限位。

5、umask

  • umask是一条命令,用来查看当前umask的值是多少,也可以更改当前umask的值:
    在这里插入图片描述

  • 创建文件的话,权限会满足 0666& ~umask 的表达式。这种机制的存在就是为了防止产生权限过松的文件

  • umask还是 一个系统调用函数,如果在进程当中想要设置这个umask的值的化,可以调用umask这个函数, 如下:
    在这里插入图片描述

6、文件权限的更改与管理 :chmod,fchmod

  • chmod 当命令时的作用是在终端上更改文件权限:
    在这里插入图片描述
    可以看到,我们将 test.c 的other权限中,加上了 w 可读的权限

  • 由于 test.c 是没有执行权限的,然后我们使用 chmod a+x test.c,给他所有用户加上可执行权限。a+x 表示的是所有用户有可执行权限,所以我们还可以使用 u+xg+x, o+x
    在这里插入图片描述

  • 如果在一个进程当中操作一个文件的时候,需要临时改变一个文件的权限信息,就需要 chmod( ) 函数与 fchmod( ) 函数, 这个是两个个系统调用函数。(前者操纵的是文件路径名,后者操纵的是文件描述符)
    在这里插入图片描述

7、粘住位( t 位)

  • t 位原始的功能:给某一个当前二进制命令设置t位,设置t位的作用是把某一个命令的使用痕迹进行保留,为的是下次再装载这个模块的时候比较快。通俗的讲就是:在内存当中保留它的使用痕迹,下次装载会比较快。通常是给一个可执行的命令进行设计。
  • 现如今这个设计无所谓了,因为有了page的设计,本来使用的内存块就会留在内存当中,所以这个 t 位在慢慢的淡化,现在常用于给目录设置 t 位。
  • 目前目录设置t位的是 /tmp/
    在这里插入图片描述给这个目录加上t位以后,各个用户对于目录的操作,以及对目录下的文件的操作就比较特殊化了。

8、文件系统:FAT,UFS

  • 文件系统:实际上是文件或者数据的存储格式问题。归根结底是为了帮助我们存储或管理文件。
  • 比如说:钱存在中国银行叫人民币,存在美国银行叫美元,但是钱是一样的。数据也是一样,只是存在在了不同的文件系统当中。

(1)FAT文件系统

  • FAT的实质是一个静态存储的单链表,, 具体的实际结构如下:
struct{
	int next[N];
	char data[N][data_size];
}

正是因为N的存在,FAT存储的文件是有限的,不能超过N个数据块。

  • 拿到windows的时候,首先第一件事是要分区,为什么要分区,因为那个时候的FAT系统承载能力有限,过多的文件或者很大的文件当前承载不了,所以说要分区。

  • FAT文件系统最大的缺陷就是使用了静态单链表,单链表最大的缺陷是一个走向,指针不能往回指。如今FAT系统还是在使用的,比如说小u盘, 小SD卡,为了轻量级。

  • 360内存清理: 用一个进程不停的吃内存吃内存(要内存),在抢资源,留在内存中的常用的数据块就在往swap交换分区去挪,当进程强占资源到一定程度的时候,就会立马结束,然后给用户提示,内存清理成功,实际上全都挤到交换分区中去了。当你用的时候,交换到swap分区中的数据又会回来,在自己逗自己玩(火绒 yyds)。

  • 注意: 当内存换出率和换入率都在直线上升的时候,才是内存吃紧的时候。

  • FAT系统特别惧怕大文件

(2)UFS文件系统

在这里插入图片描述

  • inode结构体介绍
    在这里插入图片描述

  • 如何知道哪个 inode 用了,哪个 inode 没有用?

    这里其实用到了 inode 位图,有多少个 inode 就有多少个 inode 位图,这俩一一对应着。如果 inode 用了,则与其对应的 inode 位图为 1, 如果没用,则为 0 。(数据块和数据块位图也是一样的道理)

9、硬链接,符号链接

(1)硬链接:ln

  • 通过:ln 源文件 链接文件的命令格式,可以产生硬链接

  • 本质上有点类似两个指针指向同一块区域。
    在这里插入图片描述
    这里通过 stat 命令可以查看到文件 big.c 的inode号以及硬链接数目。再使用命令:ln big.c big_link.c,结果如下:
    在这里插入图片描述
    源文件的硬链接数目变成了2,再查看生成的 big_link.c 的文件属性:
    在这里插入图片描述
    可以看到 big.c 与 big_link.c 这两个文件的 inode 号其实是一样的,所以他俩其实是指向同一个文件(这就有点类似两个指针同时指向同一块内存空间一样)。

  • 删掉源文件,硬链接文件依然有效:
    在这里插入图片描述

(2)符号链接:ln -s

  • 没有软连接,只有符号链接,不要搞混了

  • 通过:ln -s 源文件 符号链接文件格式,可以产生符号链接文件

  • 符号链接有点类似 Windows 上面的快捷方式。生成的符号链接文件和源文件其实是两个东西(文件属性不一样)
    在这里插入图片描述
    可以看到生成 test_s_link.c软链接文件后,源文件 test.c 的文件属性并没有改变,Links数目还是1:
    在这里插入图片描述
    再看 test_s_link.c 文件属性:
    在这里插入图片描述
    可以看到 test_s_link.c 的 inode 号与源文件已经不一样了。再注意:该符号链接文件的 Size 大小,其实就是源文件 名字的大小(这里是6字节)。

  • 删掉源文件,软链接文件就无效了:
    在这里插入图片描述

  • 文件权限信息开通表示的是文件类型,l表示的是链接文件(本质就是符号链接文件)
    在这里插入图片描述

(3)系统调用函数:link( )

  • 命令ln就是由该系统调用函数 link( ) 封装出来的
    在这里插入图片描述

(4)系统调用函数:unlink( )

  • 注意:利用rm删除一个文件,实质是使该文件的硬链接数为0,没有任何进程线程打开或引用该文件,此时那块数据空间才会被释放掉。(只要还有内容引用到那数据块,那就还没有删掉,即便硬链接数目已经为0了)

  • 系统调用函数:unlink( )
    在这里插入图片描述注意:使用 unlink( )可以特别容易创建匿名文件。比如,首先利用 open( )函数产生一个文件,获得一个文件描述符 fd,然后马上 unlink( )掉这个文件。但是,该文件并没有立即被删除掉,只有当 close(fd) 后,该文件才会被彻底删除。

(5)标准库函数:remove( )

  • 该函数位于 man 手册第三章,rm命令就是由该函数封装而来的
    在这里插入图片描述

(6)系统调用函数:rename( )

  • 该函数位于 man 手册第二章,mv命令就是由该函数封装而来的
    在这里插入图片描述

(7)硬链接与符号链接的特点

  • 硬链接与目录项是同义词,且建立硬链接有限制:不能给分区建立,不能给目录建立。
  • 符号链接的优点:可以跨分区,可以给目录建立

10、utime

  • 利用 ll 命令可以看到的一个时间,指的是:MTIME
    在这里插入图片描述

系统调用函数:utime( )

  • 系统调用函数:utime( ),用于修改最后一次读和修改的时间(可以修改ATIME和MTIME)
    在这里插入图片描述

11、目录的创建和销毁

(1)系统调用函数:mkdir( )

  • 命令 mkdir 就是利用mkdir( )来封装的,用于创建一个目录
    在这里插入图片描述

(2)系统调用函数:rmdir( )

  • 命令 rmdir 就是利用rmdir( )来封装的,用于删除一个目录(只能是空目录)。对于非空目录,要用递归的方式来删除
    在这里插入图片描述

12、更改当前工作路径:chdir( )

  • 命令 cd 就是由系统调用函数 chdir( ) 封装而来的
    在这里插入图片描述

13、获取当前工作路径:getcwd( )

  • 命令 pwd 就是由标准库函数 getcwd( ) 封装而来的
    在这里插入图片描述

14、分析目录与读取目录内容

(1)认识 argc 与 argv

  • argc —— 表示运行程序时,传给主函数的命令行参数个数;
  • argv[ ] —— 指针数组,存指向放传给主函数的命令行参数的地址。

例如:

#include <stdio.h>

int main(int argc, char *argv[]) {
    
    printf("argc = %d\n", argc);

    for (int i = 0; i < argc; i++)
        puts(argv[i]);

    return 0;
}

运行结果:
在这里插入图片描述
在这里插入图片描述

(2)glob( )函数:解析模式或通配符

  • glob( ) 函数用于文件系统中路径名称的模式匹配,globfree( )用来释放空间
    在这里插入图片描述

  • 参数:
    pattern——要分析的路径;
    flags——选择匹配模式,如是否排序,或者在函数第二次调用时,是否将匹配的内容追加到pglob中,不进行特殊模式匹配则写0;
    errfunc——glob函数执行出错会执行的函数,出错的路径会回填到epath中,出错的原因回填到eerrno中。如不关注错误可设置为NULL
    pglob —— 解析出来的结果放在这个参数里

  • 返回值:成功 0 失败 非0

  • 这里可以留意一下 glob_t 结构体:
    在这里插入图片描述
    gl_pathc 与 gl_pathv 有点类似于 argc 和 argv

  • 案例:

#include <stdio.h>
#include <stdlib.h>
#include <glob.h>


#define PAT "/home/mutouren/tmp/test*"

int main() {
    
    glob_t globres;

    int err = glob(PAT, 0, NULL, &globres);
    if (err) {
        printf("Error code = %d\n", err);
        exit(1);
    }   

    for (int i = 0; i < globres.gl_pathc; i++)
        puts(globres.gl_pathv[i]);

	globfree(&globres); // 释放空间

    exit(0);
}

这段代码可以打印出:/home/mutouren/tmp/ 目录下所有以 test开头的文件
在这里插入图片描述

(3)opendir( ) 与 closedir( ):打开或关闭目录文件

打开目录文件

在这里插入图片描述
关闭目录文件 (从这里可以看出,生成的 DIR 类型的数据实在堆上的)

在这里插入图片描述

(4)readdir( ):读取目录文件

  • 用于读取一个目录文件,保存在一个 dirent 结构体变量当中
    在这里插入图片描述
    dirent结构体的定义:
    在这里插入图片描述
  • 例子:打印 /home/mutouren/tmp 目录下的全部文件
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

#define PAT "/home/mutouren/tmp"

int main() {
    DIR* dp; 
    struct dirent* cur;

    dp = opendir(PAT);
    if (NULL == dp) {
        perror("opendir()");
        exit(1);
    }   

    while ((cur = readdir(dp)) != NULL)
        puts(cur->d_name);

    closedir(dp);

    return 0;
}

运行结果:
在这里插入图片描述

(5)du 命令

  • du 命令的作用:会显示指定的目录或文件所占用的磁盘空间。
    在这里插入图片描述
    这里 test.c 所占磁盘空间为 4K,也等于stat出的文件属性中的 blocks 数目除以2
    在这里插入图片描述

参考资料:请多多支持原博主

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

00后也太卷了吧!进厂起薪18K,原来面试时候都说了这些......

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该牛的还是牛。 这不&#xff0c;前段时间公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽起薪18K。本来还以为是个年少有为的技术大牛呢&#xff0c;结果相处一个月下来发现技术也就那样。 问起他是如何做到和老…

操作技巧 | Revit中如何新建系统类型并赋予颜色?

大家好&#xff0c;这里是行走的安利机---建模助手。 新建系统后&#xff0c;把材质赋予系统&#xff0c;以做出不同颜色的管道和风管系统&#xff0c;那么&#xff1a;Revit中如何新建系统类型并赋予颜色呢&#xff1f; 下面小编说下解决方案。 REVIT 具体解决办法如下 正…

每日做题总结——day01

目录 选择题 for循环 指针数组 位段 getchar 大小端存储 进制与格式控制符 位运算 数组指针 二维数组的存储 计算二进制中1的个数 斐波那契数列求递归次数 编程题 删除公共字符 排序子序列 倒置字符串 选择题 for循环 解析&#xff1a;该题主要看for…

【Java实战篇】Day6.在线教育网课平台

文章目录一、需求&#xff1a;绑定媒资1、需求分析2、库表设计与模型类3、接口定义4、Mapper层开发5、Service层开发6、完善controller层二、需求&#xff1a;课程预览1、需求分析2、实现技术3、模板引擎4、Freemarker入门5、部署网站门户6、接口定义7、接口开发8、编写模板9、…

chrome中debugger调试定位不准确

问题&#xff1a;代码中添加了debugger代码进行调试&#xff0c;但总是定位不到标注了debugger的位置 代码中debugger在33行浏览器调试定位到了78行 准确定位方法&#xff1a;

CASE WHEN函数语句多条件下使用详解

目录 CASE 的两种格式&#xff1a; 简单CASE函数 和 CASE搜索函数 同时配合 SUM 以及 COUNT 方法的使用 ① SUM函数 ② COUNT函数 CASE WHEN函数语句&#xff0c;实现简单CASE函数和CASE搜索函数两种格式。同时配合 SUM以及COUNT方法的使用 CASE 的两种格式&#xff1a; 简…

请问网络安全员,渗透师,和黑客三者是什么关系?

举个例子 黑客其实就是想偷偷进一个房子的小偷 程序员就是建这个房子的建筑工人 网络安全员就是维护这个房子的物业人员 渗透师就是检查房子【有没有能偷偷进入的窗口&#xff0c;能被撬动的锁&#xff0c;能破解的密码门】的人 有人问为什么那么多网安盯着还能让黑客进入…

深入了解jvm垃圾回收

1、为什么要有GC&#xff0c;哪些内存对象需要回收&#xff1f; 对于一个Java开发者来说&#xff0c;了解过Java内存区域的都知道&#xff0c;Java内存区域分了堆、栈、程序计数器等等。 Java的程序计数器&#xff0c;栈内存 &#xff0c;他们随线程生&#xff0c;随线程灭&a…

Alibaba开源的Java诊断工具Arthas-实战

目录参考一、启动二、支持的ognl表达式三、监听参数监听Controller 的参数和返回值监听完整参数和返回值监听kafka消费监听单个参数监听异常按照耗时进行过滤监听参数比较四、变量和方法查询静态成员变量值查询配置类具体属性的值通过类加载器查看Spring容器中对象所有属性执行…

[ 应急响应基础篇 ] 解决远程登录权限不足的问题(后门账号添加远程桌面权限)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

深入浅出Kafka

这个主题 武哥漫谈IT &#xff0c;作者骆俊武 讲得更好 一、什么是Kafka&#xff1f; 首先我们得去官网看看是怎么介绍Kafka的&#xff1a; https://kafka.apache.org/intro Apache Kafka is an open-source distributed event streaming platform. 翻译成中文就是&#xff1…

【JavaWeb】8—过滤器

⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; 如果文章对你有所帮助&#xff0c;可以点赞&#x1f44d;…

【架构师从零进阶】Java基础 练气期 Day1

目标与路径 学习周期和目标 基础&#xff1a;需要有多年的面向对象设计经验&#xff0c;至少筑基期的水平&#xff0c;为了打好基础并提升到元婴期重新学习&#xff0c;大约需要1年&#xff1b; 学习目标&#xff1a;Java 高级开发者&#xff08;元婴期&#xff09;&#xf…

旅游心得Traveling Experience

前言 加油 原文 旅游心得常用会话 ❶ Share photos of the trip with friends. 与朋友分享旅游的照片。 ❷ We’ll go to the Great Wall, if you prefer. 你如果愿意的话,我们去长城。 ❸ Would you go to the church or the synagogue or the mosque? 你会去教堂,犹太…

从零开始:如何集成美颜SDK到你的应用中

现在&#xff0c;随着人们对于美的追求不断提升&#xff0c;美颜应用已经成为了人们生活中不可或缺的一部分。在应用中&#xff0c;美颜功能的实现离不开美颜SDK的支持。那么&#xff0c;如何集成美颜SDK到你的应用中呢&#xff1f;下面&#xff0c;我们就来一步步了解。 第一…

Redis常用命令以及如何在Java中操作Redis

前言Redis是一个基于内存的key-value结构数据库&#xff0c;是互联网技术领域使用最为广泛的存储中间件。Redis基于内存存储&#xff0c;读写性能高&#xff0c;适合存储热点数据&#xff08;热点商品、资讯、新闻&#xff09;。Redis是一个开源的内存中的数据结构存储系统&…

软件测试面试复盘:技术面没有难倒我,hr面被虐的体无完肤

一般提到面试&#xff0c;肯定都会想问一下面试结果&#xff0c;我就大概的说一下面试结果&#xff0c;哈哈&#xff0c;其实不太想说&#xff0c;因为挺惨的&#xff0c;并没有像很多大佬一样 ”已拿字节阿里腾讯各大厂offer”&#xff0c;但是毕竟是自己的经历&#xff0c;无…

收割offer疯狂涨了5K,自动化测试面试题整理大全,你能答上多少?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 自动化基础能力 软件…

RBF-UKF径向基神经网络结合无迹卡尔曼滤波估计锂离子电池SOC(附MATLAB代码)

目录 RBFNN训练结果 UKF估计SOC 文章的结尾红色部分有彩蛋 RBFNN训练结果 这篇文章主要介绍如何使用RBF神经网络训练出的参数并结合UKF算法完成锂离子电池SOC的估计&#xff0c;有关RBF参数训练过程的代码分析放在2天后的下一篇文章&#xff0c;这里只给出训练完成后的结果…

在cmd命令窗口安装Python模块

Windows系统安装Python后&#xff0c;可以在cmd命令窗口安装Python的第三方库。建议选择pip命令来安装第三方库&#xff0c;因为在Python3.4及以后的版本&#xff0c;安装Python后pip模块也绑定安装了&#xff0c;其次使用pip命令很简单。 1. 一般命令 使用pip安装模块的一般…
最新文章