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

一、文件存储

一个文件主要由两部分组成,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

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

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

相关文章

Docker镜像,什么是Docker镜像,Docker基本常用命令

docker镜像 1.1什么是镜像&#xff0c;镜像基础 1.1.1 镜像的简介 镜像是一种轻量级&#xff0c;可执行的独立软件包&#xff0c;也可以说是一个精简的操作系统。镜像中包含应用软件及应用软件的运行环境&#xff0c;具体来说镜像包含运行某个软件所需的所有内容&#xff0c;…

免费领!赛盈分销联合UseePay发布《2024全球户外家居电商市场分析报告》

随着全球化的浪潮愈演愈烈&#xff0c;家居行业正在经历着深刻的变革与转型。过去几年&#xff0c;随着消费升级和科技创新的推动&#xff0c;家居行业呈现出以下几个明显趋势&#xff1a; 智能化与互联网家居 智能家居产品不断涌现&#xff0c;人们对于智能、便捷的家居生活…

Nacos 入门篇---服务端如何处理客户端的服务注册请求?(三)

一、引言 ok呀&#xff0c;上个章节我们讲了Nacos客户端的服务自动注册&#xff0c;今天我们来看看服务端接收到了客户端的服务注册请求&#xff0c;服务端都做了哪些事情&#xff5e; 二、目录 目录 一、引言 二、目录 三、回顾上节内容&#xff1a; 四、Nacos 服务代码入…

react antd 实现修改密码(原密码,新密码,再次输入新密码,新密码增加正则复杂度校验)

先看样子 组件代码&#xff1a; import React, { useState, useEffect } from react import { Row, Col, Modal, Spin, Input, Button, message, Form } from antd import { LockOutlined, EyeTwoTone, EyeInvisibleOutlined } from ant-design/icons import * as Serve from …

改进 Elastic Agent 和 Beats 中的事件队列

作者&#xff1a;Fae Charlton, Alexandros Sapranidis 内部改进如何降低 Elastic 8.13 中的内存使用。 在 8.12 版本中&#xff0c;我们引入了性能预设 —— 一种更简单的方法&#xff0c;用于调整 Elastic Agent 和 Beats 以适应各种场景。这提高了常见环境的性能&#xff0…

喜讯|我司再次获得国家发明专利,硬核科技研发成果呈加速度增长

热烈祝贺 璞华软件成功获得国家发明专利 我司自主研发成果《一种工伤案件裁决书的生成方法及装置》&#xff08;专利号&#xff1a;ZL 2019 1 1170975.8&#xff09;成功获得国家发明专利&#xff0c;2024年4月成功获得专利证书。 发明人&#xff1a;高志凯&#xff1b;杨德…

微商商城源码小程序好用么?

商城APP作为电子商务行业的重要组成部分&#xff0c;已经成为了人们购物的主要方式之一。为了在竞争激烈的市场中脱颖而出&#xff0c;开发一款专业且思考深度的商城APP方案显得尤为关键。本文将从专业性和思考深度两个方面&#xff0c;探讨商城APP的开发方案。 一、专业性的重…

BGI | STCellBin:动植物组织细胞分割

简介 STCellbin 利用细胞核染色图像作为桥梁来获取与空间基因表达图谱对齐的细胞膜/壁染色图像。通过采用先进的细胞分割技术&#xff0c;可以获得准确的细胞边界&#xff0c;从而获得更可靠的单细胞空间基因表达谱。此次更新的增强功能为细胞内基因表达的空间组织提供了宝贵的…

uc网盘推广拉新渠道

​近期&#xff0c;UC网盘拉新项目在收益上展现出了一些明显的优势&#xff0c;这些优势对于推广者来说是非常吸引人的。以下是对这些优势的详细分析&#xff1a; 上手容易&#xff1a;与其他项目相比&#xff0c;UC网盘的报备审核过程相对宽松&#xff0c;速度也更快。在快节奏…

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey

Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey PDF: https://arxiv.org/pdf/2403.14608.pdf 1 概述 大型模型在多个领域取得了显著进展&#xff0c;但它们的大规模参数带来了高昂的计算成本。这些模型需要大量资源来执行&#xff0c;尤其是在针…

【python】__name__函数的用法详解!

上一篇中&#xff0c;说到了__init__函数的使用&#xff0c;__init__函数是在类中实现&#xff0c;它在创建对象时自动执行&#xff0c;用于初始化对象的属性。今天我们来说一下__name__函数&#xff0c;__name__函数的主要作用为&#xff1a; 1.执行python脚本 2.导入到别的…

哪种裤子比较百搭?显高显瘦的男生裤子分享

选到合适的裤子才能穿得好看以及舒服。可是市面上也出现了不少各种裤子质量达不到标准的负面新闻&#xff0c;为了能够选到合适的裤子&#xff0c;我自费购买了多个品牌的裤子测评。之后我知道很多网红品牌为了压低成本&#xff0c;用料和做工都很差&#xff0c;于是我总结了五…

Python和Java哪个更适合后端开发?

Python和Java都是强大的后端开发语言&#xff0c;它们各自有鲜明的特点和适用场景。选择哪一个更适合后端开发&#xff0c;主要取决于具体的项目需求、团队技术栈、个人技能偏好以及长期发展考虑等因素。 下面是两者在后端开发中的优势和劣势&#xff1a; 「Python&#xff1…

TCP/IP协议—TCP

TCP/IP协议—TCP TCP协议TCP通信特点TCP技术概念TCP定时器 TCP头部报文TCP连接三次握手&#xff08;建立连接&#xff09;四次挥手&#xff08;释放连接&#xff09;连接状态 TCP协议 传输控制协议&#xff08;TCP&#xff0c;Transmission Control Protocol&#xff09;是一种…

《柳叶刀》子刊:突破性临床试验,证实粪菌移植治疗帕金森病的潜力

帕金森病&#xff08;Parkinson’s Disease&#xff0c;PD&#xff09;&#xff0c;是一种复杂的神经退行性疾病&#xff0c;也是世界上第二常见的神经退行性疾病&#xff0c;仅次于阿尔茨海默病&#xff08;AD&#xff09;&#xff0c;影响着约1%-2%的65岁及以上老人。随着全球…

Ribbon-负载均衡原理解析(案例)

简介&#xff1a;负载均衡&#xff0c;英文名称为Load Balance&#xff0c;其含义就是指将负载&#xff08;工作任务&#xff09;进行平衡、分摊到多个操作单元上进行运行&#xff0c;例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等&#xff0c;从而协同…

明厨亮灶厨师帽佩戴检测的难点与优化方式 Yolov5+bytetrack

随着国家一系列食品安全政策的出台&#xff0c;厨房的安全卫生问题逐渐被人们重视。其中&#xff0c;工作人员是否佩戴厨师帽是很关键的一环。人们希望能通过一种方式实现自动化的检测&#xff0c;但目前市场上大部分“明厨亮灶系统”或“未佩戴厨师帽检测系统”都无法满足用户…

【UE5.1】使用MySQL and MariaDB Integration插件——(1)连接MySQL

效果 步骤 1. 在虚幻商城下载“MySQL and MariaDB Integration”插件 2. 购买安装后&#xff0c;我们将插件添加到一个新工程中&#xff0c;打开新工程可以看到已经添加了插件 3. 新建一个蓝图&#xff0c;选择父类为“MySQLDBConnectionActor” 这里命名为该蓝图为“BP_MySQL…

腾讯测试岗位的面试经历与经验分享【一面、二面与三面】

腾讯两个月的实习一转眼就结束了,回想起当时面试的经过,感觉自己是跌跌撞撞就这么过了,多少有点侥幸.马上腾讯又要来校招了,对于有意愿想投腾讯测试岗位的同学们,写了一些那时候面试的经历和自己的想法,算不上经验&#xff0c;仅供参考吧! 一面 — —技术基础&#xff0c;全面…

linux 自定义命令/别名

参考资料 Linux(Ubuntu)自定义命令的使用Linux/Ubuntu系统自定义Shell命令Ubuntu/Linux 操作系统 自定义命令 目录 一. 为路径取别名二. 修改.profile文件2.1 .profile简介2.2 需求2.3 修改.profile文件 三. 创建软链接 一. 为路径取别名 ⏹需求&#xff1a;有一个work文件夹…