C++linux高并发服务器项目实践 day4

news2025/1/19 11:18:56

C++linux高并发服务器项目实践 day4

  • 模拟实现ls -l指令
  • 文件属性操作函数
    • access函数
    • chmod 与chown
    • truncate函数
  • 目录操作函数
    • mkdir和rmdir
    • rename
    • chdir和getcwd
  • 目录遍历函数
  • dup、dup2函数
    • dup
    • dup2
  • fcntl函数

模拟实现ls -l指令

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<string.h>
//模拟实现ls -l指令

int main(int argc ,char * argv[]){

    //判断输入的参数是否正确
    if(argc < 2){
        printf("%s filename\n",argv[0]);
        return -1;
    }

    //通过stat函数获取用户传入的信息
    struct stat st;
    int ret = stat(argv[1],&st);
    if(ret == -1){
        perror("stat");
        return -1;
    }

    //获取文件类型和文件权限
    char perms[11] = {0};//用于保存文件类型和文件权限的字符串,参见ls -l出来的参数,一共有10位,最后一位是字符串的结束符

    switch (st.st_mode)
    {
    case __S_IFLNK:
        perms[0] = 'l';
        break;
    case __S_IFDIR:
        perms[0] = 'd';
        break;
    case __S_IFREG:
        perms[0] = '-';
        break;
    case __S_IFBLK:
        perms[0] = 'b';
        break;
    case __S_IFCHR:
        perms[0] = 'c';
        break;
    case __S_IFSOCK:
        perms[0] = 's';
        break;
    case __S_IFIFO:
        perms[0] = 'p';
        break;    
    default:
        perms[0] = '?';
        break;
    }

    //判断文件的访问权限

    //文件所有者
    perms[1]=(st.st_mode & S_IRUSR)?'r':'-';
    perms[2]=(st.st_mode & S_IWUSR)?'w':'-';
    perms[3]=(st.st_mode & S_IXUSR)?'x':'-';

    //文件所在组
    perms[4]=(st.st_mode & S_IRGRP)?'r':'-';
    perms[5]=(st.st_mode & S_IWGRP)?'w':'-';
    perms[6]=(st.st_mode & S_IXGRP)?'x':'-';

    //其他人
    perms[7]=(st.st_mode & S_IROTH)?'r':'-';
    perms[8]=(st.st_mode & S_IWOTH)?'w':'-';
    perms[9]=(st.st_mode & S_IXOTH)?'x':'-';

    //硬连接数
    int linkNum = st.st_nlink;

    //文件所有者
    char * fileUser = getpwuid(st.st_uid)->pw_name;

    //文件所在组
    char * fileGrp = getgrgid(st.st_gid)->gr_name;

    //文件大小
    long int fileSize = st.st_size;

    //获取修改的时间
    char * time = ctime(&st.st_mtime);
    
    char mtime[512] = {0};
    strncpy(mtime,time,strlen(time)-1);

    char buf[1024];
    sprintf(buf,"%s %d %s %s %ld %s %s",perms,linkNum,fileUser,fileGrp,fileSize,mtime,argv[1]);

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

    return 0;
}

文件属性操作函数

  • int access(const char * pathname ,int mode);
  • int chmod(const char * filename,int mode);
  • int chown(const char* path,uid_t owner,gid_t group);
  • int truncate(const char* path,off_t length);

access函数

#include <unistd.h>
int access(const char *pathname, int mode);
作用:判断某个文件是否有某个权限,或者判断文件是否存在
参数:

  • pathname:判断文件路径
  • mode:
    R_OK:判断是否有读权限
    W_OK:判断是否有写权限
    X_OK:判断是否有可执行权限
    F_OK:判断文件是否存在

返回值:成功返回0,失败返回-1

#include <unistd.h>
#include<stdio.h>

int main(){
    int ret = access("a.txt",F_OK);
    if(ret == -1){
        perror("access");
    }

    printf("文件存在!!!\n");


    return 0;
}

chmod 与chown

CHMOD

#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
作用:修改文件的权限
参数:
- pathname:需要修改的文件的路径
- mode:需要修改的权限值,八进制的数
返回值:成功返回0,失败返回-1

#include <sys/stat.h>
#include <stdio.h>

int main()
{
    int ret = chmod("a.txt",0777);
    if(ret == -1){
        perror("chmod");
        return -1;
    }

    return 0;
}

CHOWN同理,作用为修改文件的所有者

truncate函数

#include <unistd.h>
#include <sys/types.h>

int truncate(const char *path, off_t length);
作用:缩减或者扩展文件的尺寸至指定的大小
参数:

  • path:需要修改的文件的路径
  • length:需要最终文件变成的大小

返回值:
成功返回0,失败返回-1

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

int main(){
    
    int ret = truncate("a.txt",20);

    if(ret == -1){
        perror("truncate");
    }

    return 0;
}

目录操作函数

  • int mkdir(const char *pathname,mode_t mode);
  • int rmdir(const char *pathname);
  • int rename(const char *oldpath,const char *newpath);
  • int chdir(const char *path);
  • char *getcwq(char *buf,size_t size);

mkdir和rmdir

#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
作用:创建一个目录
参数:

  • pathname:创建的目录的路径
  • mode:权限,八进制数

返回值:成功返回0,失败返回-1

最终的权限表现是mode & umask & 0777
一个目录必须要有可执行权限,才可以进入

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

int main(){
    int ret = mkdir("aaa",0777);

    if(ret == -1){
        perror("mkdir");
        return -1;
    }
    return 0;
}

rmdir只能删除空目录,必须把目录中内容全部删除后才能删除该目录

rename

#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
重命名函数

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

int main(){
    int ret = rename("aaa","bbb");

    if(ret == -1){
        perror("rename");
        return -1;
    }
    return 0;
}

chdir和getcwd

#include <unistd.h>
int chdir(const char *path);
作用:修改进程的工作目录,源工作目录就是启动进程的目录
参数:
path:需要修改的工作目录

#include <unistd.h>
char *getcwd(char *buf, size_t size);
作用:获取当前工作目录
参数:

  • buf:存储的路径,指向的是一个数组(传出参数)
  • size:数组的大小

返回值:
返回的指向的一块内存,这个数据就是第一个参数

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

int main(){

    //获取当前的工作目录
    char buf[128];
    getcwd(buf,sizeof(buf));
    printf("当前的工作目录是:%s\n",buf);

    //修改工作目录
    int ret = chdir("/home/yuuki/Linux/lesson13");
    if(ret == -1){
        perror("chdir");
        return -1;
    }

    //创建一个新文件
    int fd = open("chdir.txt",O_CREAT|O_RDWR,0664);
    if(fd == -1){
        perror("open");
        return -1;
    }

    close(fd);

    //获取当前的工作目录
    char buf1[128];
    getcwd(buf1,sizeof(buf1));
    printf("当前的工作目录是:%s\n",buf1);

    return 0;
}

目录遍历函数

  • DIR *opendir(const char *name);
  • struct dirent *readdir(DIR *dirp);
  • int closedir(DIR *dirp);

#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
作用:打开一个目录流指向目录,并且返回一个指向目录流的指针,流位于目录中的第一个实体
参数:name:需要打开的目录的名称
返回值:DIR *类型,理解为目录流
错误返回NULL

#include <dirent.h>
struct dirent *readdir(DIR *dirp);
作用:读取目录中的数据,返回一个指针指向dirent类型的结构体,代表下一个目录实体指向dirp
参数:dirp是opendir返回的结果
返回值:struct dirent,代表读取到的文件的信息
读取到了末尾或失败,返回NULL

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
作用:关闭目录

在这里插入图片描述

#define _DEFAULT_SOURCE
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int getFileNum(const char * path);

//读取某个文件下所有的普通文件的个数
int main(int argc ,char * argv[]){

    if(argc < 2){
        printf("%s path\n",argv[0]);
        return -1;
    }

    int num = getFileNum(argv[1]);

    printf("普通文件的个数为:%d\n",num);

    return 0;
}

//用于获取目录下所有普通文件的个数
int getFileNum(const char * path){
    //1.打开目录
    DIR *dir = opendir(path);

    if(dir == NULL){
        perror("opendir");
        exit(0);
    }

    struct dirent *ptr;

    //记录普通文件的个数
    int total = 0;

    while((ptr = readdir(dir))!= NULL){
        //获取名称
        char * dname = ptr->d_name;



        //忽略.和..
        if(strcmp(dname,".")==0 || strcmp(dname,"..")==0){
            continue;
        }

        //判断普通文件还是目录
        if(ptr->d_type == DT_DIR){
            //目录,需要继续读取这个目录
            char newpath[256];
            sprintf(newpath,"%s/%s",path,dname);
            total += getFileNum(newpath)
;        }

        if(ptr->d_type == DT_REG){
            //普通文件
            total++;
        }
    }
    
    //关闭目录
    closedir(dir);
    return total;
}

问题:为什么导入了#include <dirent.h>,DT_DIR、DT_REG仍然显示未定义?
解决方法:需要_DEFAULT_SOURCE宏来启用文件类型常量。
在包含dirent.h之前,可以在源代码中执行此操作
#define _DEFAULT_SOURCE
#include <dirent.h>

dup、dup2函数

  • int dup(int oldfd); 复制文件描述符
  • int dup2(int oldfd,int newfd);重定向文件描述符

dup

#include <unistd.h>
int dup(int oldfd);
作用:复制一个新的文件描述符
fd = 3,int fd1 = dup(fd),fd指向的是a.txt,fd1也是指向a.txt
从空闲的文件描述表中找一个最小的,作为新的拷贝的文件描述符

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

int main(){
    int fd = open("a.txt",O_RDWR | O_CREAT,0664);

    int fd1 = dup(fd);

    if(fd1 == -1){
        perror("dup");
        return -1;
    }

    printf("fd : %d , fd1 : %d\n",fd,fd1);

    close(fd);

    char * str = "hello,world";
    int ret = write(fd1,str,strlen(str));
    if(ret == -1){
        perror("write");
        return -1;
    }


    return 0;
}

dup2

#include <unistd.h>
int dup2(int oldfd, int newfd);
作用:重定向文件描述符

oldfd 指向a.txt,newfd指向b.txt
调用函数成功后:newfd和b.txt做close,newfd指向a.txt
oldfd必须是一个有效的文件描述符
oldfd和newfd值相同,相当于什么都没有做

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


int main(){
    int fd = open("1.txt",O_RDWR|O_CREAT,0664);
    if(fd == -1){
        perror("open");
        return -1;
    }

    int fd1 = open("2.txt",O_RDWR|O_CREAT,0664);
    if(fd1 == -1){
        perror("open");
        return -1;
    }

    printf("fd : %d, fd1 : %d\n",fd,fd1);

    int fd2 = dup2(fd,fd1);
    if(fd2 == -1){
        perror("dup2");
        return -1;
    }

    //通过fd1去写数据,实际操作的是1.txt,而不是2.txt
    char * str = "hello,dup2";
    int len = write(fd1,str ,strlen(str));

    if(len == -1){
        perror("write");
        return -1;
    }

    printf("fd : %d,fd1 : %d,fd2 : %d\n",fd,fd1,fd2);

    close(fd);
    close(fd1);

    return 0;
}

fcntl函数

int fcntl(int fd,int cmd,.../*arg*/);

复制文件描述符
设置/获取文件的状态标志

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, … );
参数:
fd:表示需要操作的文件描述符
cmd:表示对文件描述符进行如何操作

  • F_DUPFD :复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
    int ret = fcntl(fd,F_DUPFD);

  • F_GETFL:获取指定的文件描述符文件状态flag
    获取的flag和我们通过open函数传递的flag是一个东西

  • F_SETFL:设置文件描述符文件状态flag
    必选项:O_RDONLY,O_WRONLY,O_RDWR 不可以被修改
    可选项:O_APPEND,o_NONBLOCK
    O_APPEND 表示追加数据
    O_NONBLOCK 设置成非阻塞

阻塞和非阻塞:描述的是函数调用的行为。一个线程或进程没有返回值,正在执行时,能够继续进行的为非阻塞,不能的为阻塞

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

int main(){

    //1.复制文件描述符
    //int fd = open("1.txt",O_RDONLY);

    //int ret = fcntl(fd,F_DUPFD);

    //2.修改或者获取文件状态flag
    int fd = open("1.txt",O_RDWR);
    if(fd == -1){
        perror("open");
        return -1;
    }

    //3.获取文件描述符状态flag
    int flag = fcntl(fd,F_GETFL);
        if(flag == -1){
        perror("fcntl");
        return -1;
    }
    flag |= O_APPEND;  // flag = flag | O_APPEND
    
    //4.修改文件描述符状态的flag,给flag加入O_APPEND这个标记
    int ret = fcntl(fd,F_SETFL,flag);

    if(ret == -1){
        perror("fcntl");
        return -1;
    }

    char *str = "nihao";
    write(fd,str,strlen(str));

    close(fd);

    return 0;
}

虽然APPEND是追加的flag,但是要有写权限才能在文本文件中添加内容,所以在open时的参数应该是O_RDWR

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

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

相关文章

为何巴菲特和马斯克站在了一起?

股神巴菲特虽然非常传奇&#xff0c;但是马斯克对其并不感冒。马斯克曾经在一档电视节目中表示&#xff0c;实业才是王道&#xff0c;埋怨金融业抢走太多人才和精英&#xff0c;暗指巴菲特为年轻人做了错误示范。当然&#xff0c;巴菲特的投资非常厉害&#xff0c;但也有失手的…

2-修改example适用于不同开发板

1.问题 手上只有基于nRF52811芯片的BMD360开发板,与pca10056e开发板同一个芯片.所以pca10056e的example都可以适用于BMD360开发板,只需要修改开发板相同的输入输出硬件管脚即可.因为BMD360开发板与pca10056e开发板的输入输出管脚不同. 而BMD360开发板输入输出管脚于PCA10040相同…

【数据结构】七大排序算法详解Java

目录 1.排序算法分类 1.直接选择排序 代码展示&#xff1a; 2.直接插入排序 核心思路&#xff1a; 代码展示&#xff1a; ​编辑 3.希尔排序 思路分析&#xff1a; 代码展示&#xff1a; 4.归并排序 代码展示&#xff1a; 5.快速排序(挖坑法) 思路分析&#xff1a; …

OJ系统刷题 第十篇

13444 - 求出e的值 时间限制 : 1 秒 内存限制 : 128 MB 利用公式e11/!1​1/2!​1/3!​...1/n!​&#xff0c;求e的值&#xff0c;要求保留小数点后10位。 输入 输入只有一行&#xff0c;该行包含一个整数n&#xff08;2≤n≤15&#xff09;&#xff0c;表示计算e时累加到1/…

计算机操作系统第四版第六章输入输出系统—课后题答案

1.试说明I/O系统的基本功能。 隐藏物理设备的细节、与设备的无关性、提高处理机和I/O设备的利用率、对I/O设备进行控制、确保对设备的正确共享、错误处理 2.简要说明I/O软件的4个层次的基本功能。 用户层I/O软件&#xff1a;实现与用户交互的接口&#xff0c;用户可直接调用该层…

4.8、socket介绍

4.8、socket1. socket介绍1. socket介绍 所谓 socket&#xff08;套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。从所处的地位…

阿里云centos7搭建ChatGPT网站

需要的环境 有一台外网的服务器 拥有一个OpenAI API Key Centos7&#xff08;其他服务器也行&#xff09; nodejs 前端github上 大神写的 https://github.com/ddiu8081/chatgpt-demo/ 一.安装node.js centos7 安装node.js 二.安装pnpm npm i -g pnpm三.下载web前端项目从…

【2023最新】超详细图文保姆级教程:App开发新手入门(3)

上文回顾&#xff0c;我们已经完成了一个应用项目创建、导入、代码更新、代码同步和代码提交&#xff0c;本章继续我们的新手开发之旅&#xff0c;讲述一下如何将开发完成的应用进行编译&#xff0c;生成可供他人安装、可上架的应用安装包。 6 应用打包 应用打包&#xff0c;…

27个必备的Python技巧,你一定要知道!

目录 01. 为什么使用缩进来分组语句&#xff1f; Guido van Rossum 认为使用缩进进行分组非常优雅&#xff0c;并且大大提高了普通 Python 程序的清晰度。大多数人在一段时间后就学会并喜欢上这个功能。 由于没有开始/结束括号&#xff0c;因此解析器感知的分组与人类读者之间…

免费英文在线翻译-英文自动翻译

免费的自动翻译器 作为一款免费的自动翻译器&#xff0c;我们的产品可以为全球用户提供高质量、高效率的翻译服务&#xff0c;帮助他们更好地沟通和交流。 现在&#xff0c;随着数字化的进一步发展&#xff0c;人们之间的跨文化交流越来越频繁。然而&#xff0c;语言偏差和文…

22-JavaScript

目录 1.什么是JavaScript&#xff1f; 1.1.JS、HTML、CSS关系 1.2.JS是如何运行的&#xff1f; 2.JS前置知识 2.1.第一个JS程序 PS&#xff1a;JS书写位置 2.2.JS书写格式 2.2.1.行内格式 ​2.2.2.内嵌格式 ​2.2.3.外部格式 2.3.注释&#xff08;script标签中&…

【软件测试】测试用例

目录 &#x1f337;1. 测试用例的基本要素 &#x1f337;2. 测试用例的设计方法 &#x1f333;2.1 基于需求进行测试用例的设计 ⭐️&#xff08;1&#xff09;功能需求测试分析 ⭐️&#xff08;2&#xff09;非功能需求测试分析 &#x1f333;2.2 具体的设计方法 &#…

【Python搞笑游戏】因蔡徐坤打篮球动作超火,被某程序员写成了一款游戏,画面美到不敢看,成功学到了精髓~(附源码免费)

导语 之前网络最火的梗&#xff0c;非“C徐坤打篮球”莫属。个人感觉&#xff0c;只有多年前的“春哥纯爷们”堪与匹敌&#xff01; 虽然说C徐坤打篮球是一个老梗了&#xff0c;但是确实非常搞笑&#xff0c;今天就跟着小编一起来回忆一下吧&#xff01; “我是练习两年半的…

qt - 隐式共享与d-pointer技术

文章目录前言1. 隐式共享2. d-pointer在隐式共享中的应用3. 二进制代码兼容4. d-pointer模式的实现5. QObject中的d-pointer前言 一般情况下&#xff0c;一个类的多个对象所占用的内存是相互独立的。如果其中某些对象数据成员的取值完全相同&#xff0c;我们可以令它们共享一块…

ESP32学习二-更新Python版本(Ubuntu)

一、简介 在一些场景里边&#xff0c;因为Python的版本过低&#xff0c;导致一些环境无法安装。这里来介绍以下&#xff0c;如何升级自己已安装的Python版本。例如如下情况&#xff1a; 二、实操 1.查看本地版本 python --version 2.添加源 sudo add-apt-repository ppa:jona…

FPGA时序知识点(基本方法总结就两点:1.降低时钟频率2.减小组合逻辑延迟(针对Setup Slack公式来的)

1.我们说的所有时序分析都是建立在同步电路的基础上的&#xff0c;异步电路不能做时序分析&#xff08;或者说只能做伪路径约束&#xff08;在设伪路径之前单bit就打拍&#xff0c;多bit就异步fifo拉到目的时钟域来&#xff09;&#xff09;。——FPGA 设计中寄存器全部使用一个…

逐一解释一下四个 “内存屏障” 是什么

什么是内存屏障&#xff1f;硬件层⾯&#xff0c;内存屏障分两种&#xff1a;读屏障&#xff08;Load Barrier&#xff09;和写屏障&#xff08;Store Barrier&#xff09;。内存屏障有两个作⽤&#xff1a; 阻⽌屏障两侧的指令重排序&#xff1b;强制把写缓冲区/⾼速缓存中的…

Matplotlib绘图

1.散点图 X1 [[3.393533211, 2.331273381], [3.110073483, 1.781539638], [1.343808831, 3.368360954], [3.582294042, 4.679179110], [2.280362439, 2.866990263], [7.423436942, 4.696522875], [5.745051997, 3.533989803], [9.172168622, 2.51…

面试官:说说MySQL主从复制原理

MySQL Replication&#xff08;主从复制&#xff09;是指数据变化可以从一个MySQL Server被复制到另一个或多个MySQL Server上&#xff0c;通过复制的功能&#xff0c;可以在单点服务的基础上扩充数据库的高可用性、可扩展性等。 一、背景 MySQL在生产环境中被广泛地应用&…

第十四届蓝桥杯题解

声明&#xff1a;以下都无法确定代码的正确性&#xff0c;是赛时代码&#xff0c;希望大家见谅&#xff01;思路可以参考&#xff0c;等后续可以评测之后再去修改博客内错误&#xff0c;也希望大家能够指正错误&#xff01; 试题A&#xff1a;日期统计 分析&#xff1a;这道题…