Linux系统编程---文件系统

news2024/12/27 11:56:05

一、文件存储

一个文件主要由两部分组成,dentry(目录项)inode

inode本质是结构体,存储文件的属性信息,如:权限、类型、大小、时间、用户、盘块位置…

也叫做文件属性管理结构,大多数的inode都存储在磁盘上。

少量常用、近期使用的inode会被缓存到内存中。

所谓的删除文件,就是删除inode,但是数据其实还是在硬盘上,以后会覆盖掉。

 

二、文件操作

1. stat函数:获取文件属性,(从inode结构体中获取)

int stat(const char *path, struct stat *buf);

参数:

        path: 文件路径

        buf:(传出参数) 存放文件属性,inode结构体指针。

返回值:

        成功: 0

        失败: -1 errno

获取文件大小: buf.st_size

获取文件类型: buf.st_mode

获取文件权限: buf.st_mode

符号穿透:stat会。lstat不会。

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

int main(int argc,char *argv[])
{
    struct stat sbuf;
    int ret = stat(argv[1], &sbuf);
    if(ret == -1)
    {
        perror( "stat error" );
        exit(1);
    }

    printf( "file size: %ld\n" , sbuf.st_size);

    return 0;
}

查看f.c文件大小执行:

./mystat f.c

2. lstat:查看文件类型,用法同stat

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

int main(int argc,char *argv[])
{
        struct stat sbuf;
        int ret = lstat(argv[1],&sbuf);
        if (ret == -1)
        {
                perror("stat error");
                exit(1);
        }

        if (S_ISREG(sbuf.st_mode)){
                printf("It's a regular file\n");
        }else if(S_ISDIR(sbuf.st_mode)){
                printf("It's a dir\n");
        }else if (S_ISFIFO(sbuf.st_mode)){
                printf("It's a pipe\n");
        }else if(S_ISLNK(sbuf.st_mode)){
                printf("It's a sym link\n");
        }
        return 0;
}

stat会拿到符号链接指向那个文件或目录的属性---符号穿透

查看符号链接文件时不想让其穿透则使用lstat函数

首先对test.c创建一个软连接

ln -s test.c test.s/test.soft

查看改文件类型,执行以下代码:

./mystat test.s/test.soft

out:

It's a sym link

如果使用stat函数,则以上输出为:

It's a dir/It's a regular file

3.link和unlink隐式回收

int link(const char *oldpath, const char *newpath);

link函数,可以为已经存在的文件创建目录项(硬链接)

int unlink(const char *pathname);

  • unlink是删除一个文件的目录项dentry,使【硬链接数-1】
  • unlink函数的特征:清除文件时,如果文件的硬链接数到0了,没有dentry对应,但该文件仍不会马上被释放,要等到所有打开文件的进程关闭该文件,系统才会挑时间将该文件释放掉。

编程实现mv命令的改名操作:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>

int main(int argc,char *argv[])
{
        link(argv[1],argv[2]);
        unlink(argv[1]);
        return 0;
}

对tets.c改为tets1.c执行以下命令:

./mymv test.c test1.c

三、目录操作

1. getcwd函数

char *getcwd(char *buf, size_t size);

功能:获取当前进程的工作目录
参数:
        buf :缓冲区,存储当前的工作目录size :缓冲区大小
返回值:
        成功:buf中保存当前进程工作目录位置

        失败:NULL

2. chdir函数

int chdir(cohst char *path);

功能:修改当前进程(应用程序)的路径

参数:
        path:切换的路径

返回值:
        成功:0

        失败: -1

示例:

int main (void)
{
    int ret = -l;
    char buf[SIZE] ;

    //1、获取当前进程的工作目录memset(buf, 0, SIZE);
    if (NULL =getcwd(buf, SIZE))
    {
        perror("getcwd error");
        return 1;
    }

    printf( " buf: %s \n", buf);

    //2.改变当前进程的工作目录
    ret = chdir( "/home/deng");
    if (-1 ==ret)
    {
        perror ("chdir error");
        return 1;
    }

    //3.获取当前进程的工作目录memset(buf,0,SIZE);
    if (NULL == getcwd(buf,SIZE))
    {
        perror ("getcwd error");
        return 1;
    }

    printf("buf: %s\n" , buf);
}

3. opendir函数

DIR *opendir(const char *name) ;

功能:打开一个目录
参数:
        name:目录名

返回值:
        成功:返回指向该目录结构体指针

        失败:NULL

4. closedir函数

int closedir(DIR *dirp);

功能:关闭目录
参数:
        dirp: opendir返回的指针

返回值:
        成功:0

        失败: -1

示例:

//目录打开和关闭
int main(void)
{
    DIR *dir = NULL;

    //1.打开日录
    dir = opendir("test");
    if (NULL == dir)
    {
        perror ("opendir error");
        return l;
    }

    closedir(dir);
    return 0;
}

5. readdir函数

struct dirent *readdir(DIR *dirp);

功能:读取目录
参数:
        dirp: opendir的返回值

返回值:
        成功:目录结构体指针

        失败:NULL

相关结构体说明:

struct dirent{
        ino_t d_ino;        //此目录进入点的inode
        off_t d_off;        //目录文件开头至此目录进入点的位移
        signed short int d_reclen;        // d_name 的长度,不包含NULL字符
        unsigned char d_type;        // d_type所指的文件类型
        char d_name [256];        //文件名

};

实现 ls -a 代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<dirent.h>

int main(int argc,char *argv[])
{
        DIR * dp;
        dp = opendir(argv[1]);
        if (dp == NULL){
                perror("opendir error");
                exit(1);
        }

        struct dirent *sdp;
        while((sdp = readdir(dp)) != NULL){
                printf("%s\t",sdp->d_name);
        }

        printf("\n");   

        closedir(dp);

        return 0;
}

在当前目录下使用命令,执行:./myls ./ 即展示当前目录下的文件及大小

 四、递归遍历目录

任务需求:使用opendir closedir readdir stat实现一个递归遍历目录的程序

输入一个指定目录,默认为当前目录。递归列出目录中的文件,同时显示文件大小。

思路分析

递归遍历目录:ls-R.c

1. 判断命令行参数,获取用户要查询的目录名。 int argc, char *argv[1]

                argc == 1 --> ./

2. 判断用户指定的是否是目录。 stat S_ISDIR(); --> 封装函数 isFile() { }

3. 读目录: read_dir() {

                   opendir(dir)

                   while (readdir()){

                        普通文件,直接打印

                        目录:

                                拼接目录访问绝对路径。sprintf(path, "%s/%s", dir, d_name)

                                递归调用自己。--> opendir(path) readdir closedir

                     }

                     closedir()

                     }

        read_dir() --> isFile() ---> read_dir()

代码示例:

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

#define PATH_LEN 256
//dir=/homeitgan/linux  fcn=isfile

void fetchdir(const char *dir,void (*fcn)(char *))
{
        char name[PATH_LEN];
        struct dirent *sdp;
        DIR *dp;

        if ((dp = opendir(dir)) == NULL){  //打开目录失败
                //perror("fetchdir can't open");
                fprintf(stderr,"fetchdir:can't open %s\n",dir);
                return;
        }
        while ((sdp = readdir(dp)) != NULL){
                if (strcmp(sdp->d_name,".") == 0  || strcmp(sdp->d_name,"..") == 0){       //防止出现无限递归
                continue;
                }

                if (strlen(dir)+strlen(sdp->d_name)+2>sizeof(name)){
                fprintf(stderr,"fetchdir:name %s %s too long\n",dir,sdp->d_name);
                }else{
                sprintf(name,"%s/%s",dir,sdp->d_name);
                (*fcn)(name);
                }
        }
        closedir(dp);
}

void isfile(char *name)
{
        struct stat sbuf;

        if(stat(name,&sbuf) == -1){
                fprintf(stderr,"isfile:can't access %s\n",name);
                exit(1);
        }
        if ((sbuf.st_mode & S_IFMT) == S_IFDIR){
                fetchdir(name,isfile);
        }
        printf("%8ld %s\n",sbuf.st_size,name);
}


int main(int argc,char *argv[])
{
        if(argc == 1)
                isfile(".");
        else
                while (--argc > 0) //可一次查询多个目录
                        isfile(*++argv);//循环调用该函数处理各个命令行传入的目录
        return 0;
}

执行 ./ls_R test.c 可查看test.c的文件大小

执行 ./ls_R 可查看当前目录下所有文件的大小

五、文件描述符复制

1. dup和dup2

用来做重定向,本质就是复制文件描述符

重定向:

cat myls.c > out        将myls.c的东西读出再写到out文件中

cat myls.c >> out      将myls.c的东西读出再追加到out文件中

dup()和dup2()用来做重定向,本质就是复制文件描述符,使新的文件描述符也标识旧的文件描述符所标识的文件;

这个过程类似于现实生活中的配钥匙,一把钥匙对应一把锁,然后我们又去配了一把新钥匙,此时两把钥匙都可以打开锁,而dup()和dup2()也一样,原来的文件描述符和新复制出来的文件描述符都指向同一个文件,我们操作这两个文件描述符的任何一个 都能操作它所对应的文件

dup函数

int dup(int oldfd);

功能:
        通过oldfd复制出一个新的文件描述符,新的文件描述符是调用进程文件描述符表中最小可用的文件描述符,最终oldfd和新的文件描述符都指向同一个文件。
参数:
        oldfd :需要复制的文件描述符oldfd

返回值:
        成功:新文件描述符

        失败:-1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>

int main(int argc,char *argv[])
{
        int fd = open("./out",O_RDONLY);//012 ---3
        
        int newfd = dup(fd);//4

        printf("newfd = %d\n",newfd);

        return 0;
}

make之后执行输出为:newfd = 4

dup2函数:

int dup2(int oldfd,int newfd);

功能:
        通过oldfd 复制出一个新的文件描述符newfd,如果成功,newfd和函数返回值是同一个返回值,最终oldfd和新的文件描述符newfd都指向同一个文件。
参数:
        oldfd :需要复制的文件描述符
        newfd :新的文件描述符,这个描述符可以人为指定一个合法数字(0 - 1023),如果指定的数字已经被占用(和某个文件有关联),此函数会自动关闭close()断开这个数字和某个文件的关联,再来使用这个合法数字。
返回值:
        成功:返回newfd

        失败:返回-1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>

int main(int argc,char *argv[])
{
        int fd1 = open(argv[1],O_RDWR);//0123---3

        int fd2 = open(argv[2],O_RDWR);//0123---4
        
        int fdret = dup2(fd1,fd2);//返回新文件描述符fd2

        printf("fdret = %d\n",fdret);//写入fd1指向的文件
        
        int ret = write(fd2,"1234567",7);//将屏幕输入重定向给fd1所指向的文件
        
        printf("ret = %d\n",ret);
        
        dup2(fd1,STDOUT_FILENO);

        printf("-------------------886\n");

        return 0;
}

首先新建2个空白文件out和out1

make之后执行以下命令:

./dup2 out out1

首先1234567会写入out文件中,其次再将-------------------886写入out文件

int fdret = dup2(fd1,fd2);        其中fd1 = 3,fd2 = 4

把3拷贝给4,即把4指向3(out文件)

dup2(fd1,STDOUT_FILENO);        STDOUT_FILENO = 1

把3拷贝给1,即把1指向3(out文件)

此时指向out的文件描述符有三个

2. fcntl函数

  • fcntl用来改变一个【已经打开】的文件的 访问控制属性
  • 重点掌握两个参数的使用, F_GETFL,F_SETFL

int (int fd, int cmd, ...)

参数:

        fd 文件描述符

        cmd 命令,决定了后续参数个数

        获取文件状态: F_GETFL

        设置文件状态: F_SETFL

返回值:

        int flgs = fcntl(fd, F_GETFL);

        flgs |= O_NONBLOCK

        fcntl(fd, F_SETFL, flgs);

终端文件默认是阻塞读的,这里用fcntl将其更改为非阻塞读:

#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
  
#define MSG_TRY "try again\n"  
  
int main(void)  
{  
    char buf[10];  
    int flags, n;  
  
    flags = fcntl(STDIN_FILENO, F_GETFL); //获取stdin属性信息  
    if(flags == -1){  
        perror("fcntl error");  
        exit(1);  
    }  
    flags |= O_NONBLOCK;  
    int ret = fcntl(STDIN_FILENO, F_SETFL, flags);  
    if(ret == -1){  
        perror("fcntl error");  
        exit(1);  
    }  
  
tryagain:  
    n = read(STDIN_FILENO, buf, 10);  
    if(n < 0){  
        if(errno != EAGAIN){          
            perror("read /dev/tty");  
            exit(1);  
        }  
        sleep(3);  
        write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));  
        goto tryagain;  
    }  
    write(STDOUT_FILENO, buf, n);  
  
    return 0;  
}  

 fcntl实现dup描述符:

int fcntl(int fd, int cmd, ....);

cmd: F_DUPFD

参3:         

        被占用的,返回最小可用的。

        未被占用的, 返回=该值的文件描述符。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<pthread.h>

int main(int argc, char *argv[])
{
        int fd1 = open(argv[1],O_RDWR);

        printf("fd1 = %d\n",fd1);

        int newfd = fcntl(fd1,F_DUPFD,0);//0被占用,fcntl使用文件描述符表中可用的最小文件描述符返回
        printf("newfd = %d\n",newfd);

        int newfd2 = fcntl(fd1,F_DUPFD,7);//7未被占用,返回>=7的文件描述符
        printf("newfd2 = %d\n",newfd2);

        int ret = write(newfd2,"YYYYYYYYYYYYY",7);//只能写入7个
        printf("ret = %d\n",ret);

        return 0;
}

 make之后执行:

./fcntl_dup out

out:

fd1 = 3
newfd = 4
newfd2 = 7
ret = 7

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NSA发布《在数据支柱中推进零信任成熟度》报告

4月9日&#xff0c;美国国家安全局&#xff08;NSA&#xff09;发布了题为《在数据支柱中推进零信任成熟度》的报告&#xff0c;旨在于数据安全层面提供指导&#xff0c;以增强数据整体安全性并保护静态和传输中的数据。(如下图&#xff09; 一、主要内容 报告中的建议侧重于将…

程序员可以兼职的项目

程序员可以兼职的项目 私信联系我&#xff1a;15049723876&#xff08;V&#xff09;

搜索引擎广告滥用的威胁日益严重

BlueVoyant 的一份新报告发现&#xff0c;威胁行为者正在利用搜索引擎内置的广告基础设施来对毫无戒心的用户进行网络钓鱼。该博客概述了日益增长的威胁以及如何保护自己。 恶意搜索引擎广告的使用呈上升趋势&#xff0c;对全球互联网用户和公司构成重大威胁。它不是将广告中的…

mysql 查询实战2-解答

看了mysql 查询实战2-题目-CSDN博客的题目&#xff0c;继续进行解答。 6、查询⽹站访问⾼峰期 目标&#xff1a; 查询网站访问高峰时期&#xff0c;高峰时期定义&#xff1a;至少连续三天访问量>1000 1&#xff0c;关联查询 要连续三天&#xff0c;至少要声明“自身”三个去…

二叉树经典OJ题(2)

一、根据二叉树创建字符串 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public://前序遍历&#xff1a;根 左 右//左子树为空&#xff0c;右子树不为空的时候&#xff0c;不能省略左//左不为空&#xff0c;右子树为空的时候&#xff0c;可以省略右//都为空&am…

PaddleDetection 项目使用说明

PaddleDetection 项目使用说明 PaddleDetection 项目使用说明数据集处理相关模块环境搭建 PaddleDetection 项目使用说明 https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.7/configs/ppyoloe/README_cn.md 自己项目&#xff1a; https://download.csdn.net/d…

ActiveMQ入门案例(queue模式和topic模式)

目录 前言&#xff1a;为什么使用消息中间件&#xff1f; 异步通信 缓冲 解耦 前提&#xff1a;安装并启动activemq 一、点对点&#xff08;point to point&#xff0c; queue&#xff09; 1.1 创建maven项目 1.2 Pom依赖 1.2 JmsProduce 消息生产者 1.3 JmsConsumer…

数据结构课程设计选做(三)---公共钥匙盒(线性表,栈,队列)

2.3.1 题目内容 2.3.1-A [问题描述] 有一个学校的老师共用N个教室&#xff0c;按照规定&#xff0c;所有的钥匙都必须放在公共钥匙盒里&#xff0c;老师不能带钥匙回家。每次老师上课前&#xff0c;都从公共钥匙盒里找到自己上课的教室的钥匙去开门&#xff0c;上完课后&…

FJSP:袋鼠群优化(Kangaroo Swarm Optimization ,KSO)算法求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题&#xff08;Flexible Job Shop Scheduling Problem&#xff0c;FJSP&#xff09;&#xff0c;是一种经典的组合优化问题。在FJSP问题中&#xff0c;有多个作业需要在多个机器上进行加工&#xff0c;每个作业由一系列工序组成&a…

AliyunCTF 2024 - BadApple

文章目录 前言环境搭建漏洞分析漏洞利用参考 前言 本文首发于看雪论坛 https://bbs.kanxue.com/thread-281291.htm 依稀记得那晚被阿里CTF支配的恐惧&#xff0c;今年的阿里CTF笔者就做了一道签到PWN题&#xff0c;当时也是下定决心要学习 jsc pwn 然后复现这道 BadApple 题目…

Paper Reading: MixTeacher:半监督目标检测中利用混合尺度教师挖掘有前景的标签

目录 简介目标/动机工作重点方法训练 实验总结 简介 题目&#xff1a;《MixTeacher: Mining Promising Labels with Mixed Scale Teacher for Semi-Supervised Object Detection》&#xff0c; CVPR 2023 日期&#xff1a;2023.3.16 单位&#xff1a;腾讯&#xff0c;上海交…

Upload-labs(Pass-14 - Pass-16)

Pass-14 &#xff08;图片马&#xff0c;判断文件类型&#xff09; 图片的格式在防护中通常是不会使用后缀进行判断的依据&#xff0c;文件头是文件开头的一段二进制码&#xff0c;不同类型的图片也就会有不同的二进制头。   JPEG (jpg)&#xff0c;文件头&#xff1a;FF D…

【数据挖掘】实验6:初级绘图

实验6&#xff1a;初级绘图 一&#xff1a;实验目的与要求 1&#xff1a;了解R语言中各种图形元素的添加方法&#xff0c;并能够灵活应用这些元素。 2&#xff1a;了解R语言中的各种图形函数&#xff0c;掌握常见图形的绘制方法。 二&#xff1a;实验内容 【直方图】 Eg.1&…

【数据结构】4.List的介绍

目录 1.什么是List 2.常见接口介绍 3.List的使用 1.什么是List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下&#xff1a; Iterable也是一个接口…

C语言100道练习题打卡(1)

1 有1&#xff0c;2&#xff0c;3&#xff0c;4四个数字&#xff0c;能组成多少个互不相同且不重复的三位数&#xff0c;都是多少 #include<stdio.h> //有1&#xff0c;2&#xff0c;3&#xff0c;4四个数字&#xff0c;能组成多少个互不相同且不重复的三位数&#xff…

JCR1区局部强化优化器(PRO),原理详解,MATLAB代码免费获取

局部强化优化器&#xff08;Partial Reinforcement Optimizer, PRO&#xff09;代表了进化计算领域的一项创新突破&#xff0c;它是一种全新设计的进化优化算法。该算法的开发灵感来源于心理学中的进化学习和训练理念&#xff0c;特指为一个被称为局部强化效应&#xff08;Part…

特征匹配方法总结梳理

特征匹配在视觉定位、同时定位和映射(SLAM)、图像拼接等方面都有应用 Proj:202404 CMC-R(R.W.--Reference) 南京 河海大学 资助丰富Fundamental Research Funds of China for the Central Universities, Grant/Award Number: B230205048; Jiangsu Higher Education Reform …

day10 | 栈与队列 part-2 (Go) | 20 有效的括号、1047 删除字符串中的所有相邻重复项、150 逆波兰表达式求值

今日任务 20 有效的括号 (题目: . - 力扣&#xff08;LeetCode&#xff09;)1047 删除字符串中的所有相邻重复项 (题目: . - 力扣&#xff08;LeetCode&#xff09;)150 逆波兰表达式求值 (题目: . - 力扣&#xff08;LeetCode&#xff09;) 20 有效的括号 题目: . - 力扣&…

【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控件位置

往期回顾 【QT入门】 Qt自定义控件与样式设计之QSlider用法及qss-CSDN博客 【QT入门】Qt自定义控件与样式设计之qss的加载方式-CSDN博客 【QT入门】Qt自定义控件与样式设计之控件提升与自定义控件-CSDN博客 【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控…

YOLOV5 + 双目相机实现三维测距(新版本)

文章目录 YOLOV5 双目相机实现三维测距&#xff08;新版本&#xff09;1. 项目流程2. 测距原理3. 操作步骤和代码解析4. 实时检测5. 训练6. 源码下载 YOLOV5 双目相机实现三维测距&#xff08;新版本&#xff09; 本文主要是对此篇文章做一些改进&#xff0c;以及解释读者在…