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

news/2024/12/21 17:09:16/

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

  • 文件IO
    • 标准C库IO函数与LinuxIO函数
    • 虚拟地址空间
    • 文件描述符
    • Linux系统IO函数
      • open与close
    • mode:八进制的数,表示用户对创建出的新的文件的操作权限 最终的权限是:mode & ~umask 0777 r(读) w(写) x(可执行)都有这样的权限即都是1,换算成8进制就是7 三个7分别代表当前用户,当前用户所在组的权限,其他组的权限 可以通过umask来查询本机的umask的值是多少 我这里查到的是0002取反后为0775 0777 -> 11111111 & 0775 -> 11111101
      • read和write
      • lseek函数
      • stat与lstat

文件IO

内存===文件
从文件到内存为I
从内存到文件为O

标准C库IO函数与LinuxIO函数

标准C库IO函数
在这里插入图片描述

man 3 fopen
可以打开linux的操作手册关于fopen的相关资料

同样的

man 3 fwrite

linux自带的读写,使用一次就会读一次或写一次磁盘,效率其实不如c标准库的高

在这里插入图片描述

在vscode中,写入FILE,ctrl加左键可以进入他的定义,发现他的原型是_IO_FILE,再次ctrl加左键,发现该结构体中,有char*类型的各个变量用于读写和缓冲

虚拟地址空间

在这里插入图片描述
只有实际内存空间会出现的问题:

  1. 当剩余内存不足以跑下一个程序时,运行会失败
  2. 当前面的程序释放后,虽然剩余空间能跑下一个程序,但是内存是分割开的

利用MMU(内存管理单元)来进行虚拟内存和物理内存之间的管理和转换

文件描述符

在Linux的内核区,有一个PCB(进程控制块),可以控制文件描述符
文件描述符存储在文件描述符表内,文件描述符表在数据结构上是数组形式,表的默认大小为1024
在这里插入图片描述
文件描述符表的前三位是固定的
就是标准输入、标准输出、标准错误,默认是打开状态
/dev/tty 通过上述3位可以找到当前绑定的设备终端
他们对应的终端是同一个
一个文件能被打开多次,但是多次打开的文件描述符是不一样的
在fopen打开一个文件时,一个文件描述符被占用,只有将其fclose或以linux内部的close关闭后,这个文件描述符才能再次启用
内核会自己寻找空闲的最小的文件描述符

Linux系统IO函数

int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
int close(int fd);
ssize_t read(int fd,void *buf,size_t count);
ssize_t write(int fd,const void *buf,size_t count);
off_t lseek(int fd,off_t offset,int whence);
int stat(const char *pathname.struct stat *statbuf);
int lstat(const char *pathname,struct stat *statbuf);

open与close

虽然函数重载是c++的内容,但是上述函数是C语言的,所以两个open其实是采用可变参数的方式实现的

open函数的声明在fcntl.h这个头文件内,open内部的flags定义了一些宏,放到另外两个头文件中

第一个open函数用于打开一个已经存在的文件
int open(const char *pathname,int flags);
参数:

  • pathname:要打开的文件路径
  • flags:对文件的操作权限及其他设置
    O_RDONLY,O_WRONLY,O_RDWR 这三个设置是互斥的

返回值:

  • 返回一个新的文件描述符,如果调用失败,返回-1

errno:属于Liux系统函数库,库里面的一个全局变量,记录的是最近的错误号

/*#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>//打开一个已经存在的文件int open(const char *pathname, int flags);参数:- pathname:要打开的文件路径- flags:对文件的操作权限及其他设置O_RDONLY,O_WRONLY,O_RDWR  这三个设置是互斥的返回值:返回一个新的文件描述符,如果调用失败,返回-1errno:属于Liux系统函数库,库里面的一个全局变量,记录的是最近的错误号#include <stdio.h>void perror(const char *s);s参数:用户描述,比如hello,最终输出的内容是 hello:xxx(实际错误描述)作用:打印errno对应的错误描述//创建一个新的文件int open(const char *pathname, int flags, mode_t mode);#include <unistd.h>int close(int fd);*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>int main(){int fd = open("a.txt",O_RDONLY);if(fd == -1){perror("open");}//关闭close(fd);return 0;
}

第二个open函数用于创建一个新的文件
int open(const char *pathname,int flags,mode_t mode);
参数:

  • pathname:要打开的文件路径

  • flags:对文件的操作权限及其他设置
    - 必选项:O_RDONLY,O_WRONLY,O_RDWR
    - 可选项:O_CREAT 文件不存在创建文件

  • mode:八进制的数,表示用户对创建出的新的文件的操作权限
    最终的权限是:mode & ~umask
    0777 r(读) w(写) x(可执行)都有这样的权限即都是1,换算成8进制就是7
    三个7分别代表当前用户,当前用户所在组的权限,其他组的权限
    可以通过umask来查询本机的umask的值是多少
    我这里查到的是0002取反后为0775
    0777 -> 11111111
    & 0775 -> 11111101

            11111101
    

    按位与:0和任何数都为0
    umask的作用就是抹去某些权限

    可以用umask 后面跟上数值来修改例如 umask 022
    但是这个修改只能作用在本窗口,新开一个窗口就会失效

read和write

read:
头文件: #include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
参数:

  • fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
  • buf:需要读取数据存放的缓冲区,数组的地址(传出参数)
  • count:指定的数组的大小

返回值:

  • 成功:
    》0:返回实际的读取到的字节数
    =0:文件已经读取完了
  • 失败: -1,并且设置errno

write:
头文件: #include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
参数:

  • fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
  • buf:要往磁盘写入的数据,数组
  • count:要写的数据的实际的大小

返回值:

  • 成功:实际写入的字节数
  • 失败:返回-1,并且设置errno
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{//1.通过open打开english.txt文件int srcfd = open("english.txt",O_RDONLY);if(srcfd == -1){perror("open");return -1;}//2.创建一个新的文件(拷贝文件)int destfd = open("cpy.txt",O_WRONLY|O_CREAT,0664);if(destfd == -1){perror("open");return -1;}//3.频繁的读写操作char buf[1024] = {0};int len = 0;while(( len = read(srcfd,buf,sizeof(buf))) > 0){write(destfd,buf,len);}//4.关闭文件close(destfd);close(srcfd);return 0;
}

lseek函数

标准C库的函数
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

Linux系统函数
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
第一个头文件放了一些宏定义,第二个头文件是unix的标准头文件

参数:

  • fd:文件描述符,通过open得到的,通过这个fd操作某个文件
  • offset:偏移量
  • whence:
    SEEK_SET:设置文件指针的偏移量
    SEEK_CUR:设置偏移量:当前位置+第二个参数offset的值
    SEEK_END:设置偏移量:文件大小+第二个参数offset的值

作用:

  1. 移动文件指针到头文件
    lseek(fd,0,SEEK_SET);

  2. 获取当前文件指针的位置
    lseek(fd,0,SEEK_CUR);

  3. 获取文件长度
    lseek(fd,0,SEEK_END);

  4. 拓展文件的长度,当前文件10b,110b,增加了100个字节
    lseek(fd,100,SEEK_END);
    注意:需要写一次数据

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(){int fd = open("hello.txt",O_RDWR);if(fd == -1){perror("open");return -1;}//扩展文件的长度int ret = lseek(fd,100,SEEK_END);if(ret == -1){perror("lseek");return -1;}//写入一个空数据write(fd," ",1);//关闭文件close(fd);return 0;
}

stat与lstat

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

int stat(const char *pathname, struct stat *statbuf);

作用:获取一个文件相关的一些信息
参数:

  • pathname:操作的文件的路径
  • statbuf:结构体变量,传出参数,用于保存获取到的文件的信息

返回值:

  • 成功:返回0
  • 失败:返回-1,设置errno

int lstat(const char *pathname, struct stat *statbuf);

作用:获取软链接文件本身的信息
参数:

  • pathname:操作的文件的路径
  • statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
    返回值:
  • 成功:返回0
  • 失败:返回-1,设置errno
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>int main(){struct stat statbuf;int ret = stat("a.txt",&statbuf);if(ret == -1){perror("stat");return -1;}printf("size:%ld\n",statbuf.st_size);return 0;
}

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

stat a.txt

可以查看a的一些信息

ln -s a.txt b.txt

创建一个软链接文件b.txt指向a.txt
若这里使用stat访问b.txt,则实际访问的是a.txt的信息
若想要访问b.txt本身,则需要lstat


http://www.ppmy.cn/news/47024.html

相关文章

Linux 的 grep 命令使用大全

当你需要在Linux或Unix系统中快速搜索文件中的特定字符串时&#xff0c;grep命令是非常有用的工具。Grep是Global Regular Expression Print的缩写&#xff0c;它是一个文本搜索工具&#xff0c;可以用来在一个或多个文件中查找文本模式。在这篇博客中&#xff0c;我将会讲解gr…

FPGA基于SFP光口实现1G千兆网UDP通信 1G/2.5G Ethernet PCS/PMA or SGMII替代网络PHY芯片 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案4、vivado工程详解5、上板调试验证并演示6、福利&#xff1a;工程代码的获取 1、前言 目前网上的fpga实现udp基本生态如下&#xff1a; 1&#xff1a;verilog编写的udp收发器&#xff0c;但不带ping功能&#xff0c;这样的代…

Spark 实现重新分区 partitionBy、coalesce、repartition(附代码演示)

文章目录 1、partitionBy 源码中的定义&#xff08;部分&#xff09; 调用方式 2、coalesce 源码中的定义 调用方式 3、repartition 源码中的定义 调用方式 repartition和coalesce的区别 代码演示 &#xff08;跳转代码&#xff09; 实现重新分区&#xff0c;本质上…

C++ [图论算法详解] 欧拉路欧拉回路

蒟蒻还在上课&#xff0c;所以文章更新的实在慢了点 那今天就来写一篇这周刚学的欧拉路和欧拉回路吧 讲故事环节&#xff1a; 在 一个风雪交加的夜晚 18世纪初普鲁士的哥尼斯堡&#xff0c;有一条河穿过&#xff0c;河上有两个小岛&#xff0c;有七座桥把两个岛与河岸联系…

linux知识

1.vi 删除-dd i-insert 最后一行-G 第一行-g 查找-/ 替换-:s/old/new/g 2.wc -》 行数 字符数 字节数 -w 统计字数 3. sort -k 按某一列排序 -r reverse -n 按字符排 4.uniq -c 统计重复数量 5.head -4 取文件前4行 6.date --date"1 days ago" date "%Y%m%D %H…

Python 单样本学习实用指南:1~6 全

原文&#xff1a;Hands-On One-shot Learning with Python 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心如…

C learning_6

目录 语句的种类 C语言&#xff1a;结构化是程序设计语言 顺序结构&#xff1a; 选择结构(分支结构): 循环结构&#xff1a; while语句中的break和continue 语句的种类 1.表达式语句&#xff1a;表达式语句是指一个表达式后面跟随一个分号的语句。 #include<stdio.h&g…

2021地理设计组二等奖:基于GIS的东江源区土壤侵蚀及其影响因素空间分析

一、作品背景 水土保持情况普查对我国具有重要意义。我国目前是世界上水土流失最严重的国家之一&#xff0c;水土流失面积极其广且量大&#xff1b;严重的水土流失问题是我国生态环境问题的重要板块&#xff0c;若是持续恶化&#xff0c;将会严重影响我国的生态安全、饮水安全…