linux并发服务器 —— 文件IO相关函数(三)

文件IO

以内存为主体,看待输入输出;

标准C库IO函数带有缓冲区,效率较高;

虚拟地址空间

虚拟地址空间是不存在的,一个应用程序运行期间对应一个虚拟地址空间;

虚拟地址空间的大小由CPU决定,位数不同,大小不同;

32位的机器,虚拟地址空间如下所示:

 虚拟空间会被逻辑管理单元MMU映射到真实的物理内存;

调用linux系统API(系统调用)对内核区进行操作;

文件描述符

位于进程的内核区,由PCB管理,用于定位文件,通过其实现对文件的操作;

PCB中通过数组管理文件描述符,最大为1024,前三个为0-标准输入、1-标准输出、2-标准错误,默认打开;

标准输入、标准输出、标准错位指向当前同一终端(设备文件);

不同的文件描述符对应不同的文件,一个文件可以被打开多次,多次打开的文件描述符不同

文件描述符的分配,去文件描述符表中找最小的没有分配的文件描述符进行分配即可;

Linux系统的IO函数

open打开文件

/*#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>// flags标记 宏定义在前两个头文件// 打开一个已经存在的文件int open(const char *pathname, int flags); 参数:pathname - 文件路径flags - 对文件的操作权限设置和其他设置只读、只写、读写 设置互斥( O_RDONLY,  O_WRONLY,  or O_RDWR)返回值:返回文件描述符,调用失败返回-1errno:属于Linux系统函数库,库里的全局变量,记录最近的错误号可以通过perror打印errno对应的错误描述// 创建一个新的文件int open(const char *pathname, int flags, mode_t mode);
*/#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(){int fd = open("a.txt" , O_RDONLY);if(fd==-1){perror("open");}// 关闭文件描述符 使其不指向任何文件close(fd);return 0;
}

open创建新文件

/*#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int open(const char *pathname, int flags, mode_t mode);新参数:flags - 操作权限和其他设置;必选项:操作权限;可选项:O_CREATE 文件不存在创建新文件int类型 32位 每一位都是一个标志位mode - 8进制的数,表示用户对创建出新的文件的操作权限最终权限:mode&~umask(不同用户umask不同,可以改)eg. 0777 - 最高权限  0777&~0002->0775
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(){//创建新的文件int fd = open("create.txt" , O_RDWR|O_CREAT , 0777);if(fd==-1){perror("open");}close(fd);return 0;
}

read、write函数

/*#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);参数:fd - 文件描述符 open得到 通过文件描述符操作文件buf - 读取数据存放的地方 数组的地址count - 指定数组大小返回值成功 >0 实际读取字节数=0 文件读取完了失败-1 并设置errnossize_t write(int fd, const void *buf, size_t count);参数:buf - 往磁盘写入的数据count - 要写的数据实际大小
*/#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(){// 1. open开int sfd = open("english.txt" , O_RDONLY);if(sfd==-1){perror("open");return -1;}// 2. 创建新的文件int dfd = open("cpy.txt" , O_WRONLY | O_CREAT , 0664);if(dfd==-1){perror("open");return -1;}// 3. 读写char buf[1024] = {0};int len = 0;while((len = read(sfd, buf, sizeof(buf)))>0){write(dfd , buf , len);}// 4. 关闭文件close(dfd);close(sfd);return 0;
}

lseek函数

/*#include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);参数:fd - 文件描述符offset - 偏移量whence - 指定标记:SEEK_SET设置文件指针偏移量SEEK_CUR从当前位置设置偏移量SEEK_END从文件结尾设置偏移量返回值:文件指针的位置作用:1. 移动文件指针到头文件lseek(fd , 0 , SEEK_SET);2. 获取当前文件指针位置lseek(fd , 0 , SEEK_CUR);3. 获取文件长度lseek(fd , 0 , SEEK_END);4. 拓展文件长度 10b->110blseek(fd , 100 , SEEK_END);
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>int main(){int fd = open("hello.txt" , O_RDWR);if(fd == -1){perror("open");return -1;}// 扩展文件长度int cnt = lseek(fd , 100 , SEEK_END);if(cnt == -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 设置errnoint lstat(const char *pathname, struct stat *statbuf);参数:pathname - 操作文件路径statbuf - 结构体变量(传出参数) 用于保存获取到的文件信息返回值:成功 - 0失败 - -1 设置errno
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>int main(){struct stat statbuf;int cnt = stat("a.txt" , &statbuf);if(cnt==-1){perror("stat");return -1;}printf("size: %ld\n" , statbuf.st_size);return 0;
}

stat和lstat的区别在于软链接情况;stat通过软链接查源头文件,lstat不会;

模拟实现ls -l命令

列出当前目录下的文件信息;

// 模拟实现 ls-l指令
// -rw-rw-r-- 1 nowcoder nowcoder 10 8月  28 11:02 a.txt#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>// argc>=1 - 文件名称
int main(int argc , char* argv[]){// 判断输入参数的正确性if(argc<2){printf("%s filename\n" , argv[0]);return -1;}// 通过stat获取传入文件信息struct stat st;int cnt = stat(argv[1] , &st);if(cnt == -1){perror("stat");return -1;}// 获取文件类型和文件权限char perms[11] = {0}; // 用于保存文件类型和文件权限// 文件类型switch(st.st_mode & __S_IFMT){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':'-';// OTHERSperms[7] = (st.st_mode & S_IROTH)?'r':'-';perms[8] = (st.st_mode & S_IWOTH)?'w':'-';perms[9] = (st.st_mode & S_IXOTH)?'x':'-';// 硬连接数int ln = st.st_nlink;// 文件所有者char* ur =  getpwuid(st.st_uid)->pw_name;// 文件所在组char* grp = 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];printf("%s\n" , argv[0]);sprintf(buf , "%s %d %s %s %ld %s %s" , perms , ln , ur , grp , filesize , mtime , argv[1]);printf("%s\n" , buf);return 0;
}

文件属性操作函数

acess - 判断文件权限

/*#include <unistd.h>int access(const char *pathname, int mode);作用:判断文件是否由每个权限 或文件是否存在参数:pathname - 文件路径mode  F_OK 文件是否存在R_OK 是否有读权限W_OK 是否有写权限X_OK 是否有执行权限返回值成功 - 0失败 - -1
*/#include <unistd.h>
#include <stdio.h>int main(){int ret = access("a.txt" , F_OK);if(ret == -1){perror("access");return -1;}printf("文件存在\n");return 0;
}

chmod - 修改文件权限

/*#include <sys/stat.h>int chmod(const char *pathname, mode_t mode);参数:mode - 需要修改的权限值 八进制rwx返回值:成功 - 0失败 - -1
*/
#include <sys/stat.h>
#include <stdio.h>
int main(){int ret = chmod("a.txt" , 0775);if(ret == -1){perror("chmod");return -1;}printf("修改成功\n");return 0;
}

 

chown - 修改文件所有者/所有组

//通过 vim /etc/group 查所属组 和 id
// id 用户名可查uid 和 gid
#include <unistd.h>int chown(const char *pathname, uid_t owner, gid_t group);

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("b.txt" , 20);if(ret==-1){perror("truncate");return -1;}printf("修改文件大小成功");return 0;}

目录操作函数

 mkdir

/*#include <sys/stat.h>#include <sys/types.h>int mkdir(const char *pathname, mode_t mode);作用:创建目录参数:pathname - 创建的目录路径mode - 权限 八进制返回值:成功 - 0失败 - -1
*/
#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;}printf("创建目录成功\n");return 0;
}

rmdir - 只能删除空目录

rename - 文件的重命名

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/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main(){// 获取当前路径char buf[128];getcwd(buf , sizeof(buf));printf("当前工作目录:%s\n" , buf);// 改目录int ret = chdir("/home/nowcoder/linux/lesson13");if(ret == -1){perror("chdir");return -1;}printf("已切换目录\n");int fd = open("chdir.txt" , O_RDWR|O_CREAT , 0664);if(fd == -1){perror("open");return -1;}close(fd);char buf1[128];getcwd(buf1 , sizeof(buf1));printf("当前工作目录:%s\n" , buf1);return 0;
}

目录遍历函数

opendir

readdir

closedir

/*// 打开一个目录#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *name);参数:name - 打开目录名返回值:DIR* - 目录流信息错误返回NULL// 读取目录中的数据#include <dirent.h>struct dirent *readdir(DIR *dirp);参数:dirp - opendir返回的结果返回值:struct dirent * - 读取到的文件信息读到末尾/失败 返回NULL// 关闭目录#include <sys/types.h>#include <dirent.h>int closedir(DIR *dirp);参数:opendir的返回值*/
#define _DEFAULT_SOURCE
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int getnum(const char* path);
// 读某个目录下所有普通文件的个数
int main(int argc , char *argv[]){if(argc<2){printf("%s path\n" , argv[0]);return -1;}int num = getnum(argv[1]);printf("普通文件个数:%d\n" , num);return 0;
}// 用于获取目录下所有普通文件个数
int getnum(const char* path){// 1. 打开目录DIR* dir = opendir(path);if(dir == NULL){perror("opendir");return -1;}// 2. 读取struct dirent *ptr;// 普通文件个数int tol = 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);tol += getnum(newpath);}if(ptr->d_type == DT_REG){// 普通文件tol++;}}closedir(dir);return tol;
}

dup、dup2函数

dup - 复制文件描述符

/*#include <unistd.h>int dup(int oldfd);作用:复制一个新的文件描述符(指向同一文件)int dup2(int oldfd, int newfd);*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.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";int ret = write(fd1 , str , strlen(str));if(ret == -1){perror("write");return -1;}close(fd1);return 0;
}

dup2 - 重定向文件描述符

/*#include <unistd.h>int dup2(int oldfd, int newfd);作用:重定向文件描述符 若newfd被使用 会先关闭在指若oldfd==newfd 不做任何操作
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.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("open");return -1;}// 通过fd1写数据char* str = "hello";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函数

1. 复制文件描述符;2. 设置/获取文件状态标志

/*#include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd, ...  );参数:fd - 需要操作的文件描述符cmd - 对文件描述符的操作1. 复制文件描述符 F_DUPFD2. 获取指定文件描述符文件状态flag(同open) F_GETFL3. 设置指定文件描述符文件状态 F_SETFLO_APPEND 追加数据O_NOnBLOCK 设置成非阻塞
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>int main(){// 复制文件描述符// int fd = open("1.txt" , O_RDONLY);// int ret = fcntl(fd , F_DUPFD);// 2. 修改/获取文件状态标志int fd = open("1.txt" , O_RDWR);if(fd == -1){perror("open");return -1;}// 获取flagint flag = fcntl(fd , F_GETFL);if(flag == -1){perror("fcntl");return -1;}flag |= O_APPEND;// 修改flagint 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;
}

Node: 一定要注意 如果一个文件的权限是只读 即使通过fcntl设置了O_APPEND还是不能往文件里写

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》的改进

《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》使用的Activex DLL公共对象是需要先注册的。https://blog.csdn.net/weixin_45707491/article/details/132437502?spm1001.2014.3001.5501 Activex DLL事前注册&#xff0c;一次多用说起来也不是啥大问题&#x…

R语言常用数学函数

目录 1. - * / ^ 2.%/%和%% 3.ceiling,floor,round 4.signif,trunc,zapsamll 5.max,min,mean,pmax,pmin 6.range和sum 7.prod 8.cumsum,cumprod,cummax,cummin 9.sort 10. approx 11.approx fun 12.diff 13.sign 14.var和sd 15.median 16.IQR 17.ave 18.five…

css元素定位:通过元素的标签或者元素的id、class属性定位,还不明白的伙计,看这个就行了!

前言 大部分人在使用selenium定位元素时&#xff0c;用的是xpath元素定位方式&#xff0c;因为xpath元素定位方式基本能解决定位的需求。xpath元素定位方式更直观&#xff0c;更好理解一些。 css元素定位方式往往被忽略掉了&#xff0c;其实css元素定位方式也有它的价值&…

WPF自定义命令及属性改变处理

1、项目建构 2、自定义命令 namespace WpfDemo.Base {public class MyCommand : ICommand{Action executeAction;public MyCommand(Action action){executeAction action;}public event EventHandler? CanExecuteChanged;public bool CanExecute(object? parameter){retu…

【从零开始学习JAVA | 第四十六篇】处理请求参数

前言&#xff1a; 在我们之前的学习中&#xff0c;我们已经基本学习完了JAVA的基础内容&#xff0c;从今天开始我们就逐渐进入到JAVA的时间&#xff0c;在这一大篇章&#xff0c;我们将对前后端有一个基本的认识&#xff0c;并要学习如何成为一名合格的后端工程师。今天我们介绍…

北京筑龙受邀出席中物联“采购供应链中国行—走进雄安”活动

日前&#xff0c;“采购供应链中国行—走进雄安”活动在河北雄安新区成功举办&#xff0c;来自30家相关单位的50余名领导和代表参加了本次活动。活动由中国物流与采购联合会公共采购分会主办&#xff0c;中国物流与采购联合会采购委、中国雄安集团有限公司、河北雄安新区招标投…

在 Python 中逐步构建 DCF(贴现流)估值

Building A DCF Valuation in Python, Step by Step | by Roi Polanitzer | Medium 说明 这是一个真实的&#xff0c;以色列国土内的公司业务评估案例。在本文中&#xff0c;我将演示如何使用python中的DCF方法对以色列系统和应用程序公司进行业务评估。因为存在许多业务术语&a…

Jmeter(二十八):beanshell的使用

Beanshell 是一种轻量级的 Java 脚本,纯 Java 编写的,能够动态的执行标准 java 语法及一些扩展脚本语法,类似于 javaScript,在工作中可能用的多的就是: Beanshell 取样器:跟Http取样器并列Beanshell前置处理器:一般放在Http请求下,在请求前处理一些数据Beanshell后置处…

万级数据优化EasyExcel+mybatis流式查询导出封装

文章目录 前言.千万级数据优化一. 直接上流式查询封装工具代码二. 传统分页导出查询三. 流式查询概念游标查询 前言.千万级数据优化 我们不妨先给大家讲一个概念&#xff0c;利用此概念我们正好给大家介绍一个数据库优化的小技巧&#xff1a; 需求如下&#xff1a;将一个地市表…

【conda install】网络慢导致报错CondaHTTPError: HTTP 000 CONNECTION FAILED for url

⭐⭐问题&#xff1a; 部署安装环境经常会出现由于网络慢问题&#xff0c;导致conda安装不了库&#xff0c;报错如下&#xff1a; Solving environment: failedCondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/…

c#在MVC Api(.net framework)当中使用Swagger,以及Demo下载

主要的步骤就是创建项目&#xff0c;通过nuget 添加Swashbuckle包&#xff0c;然后在SwaggerConfig当中进行相关的配置。 具体的步骤&#xff0c;可以参考下面的链接&#xff1a; https://www.cnblogs.com/94pm/p/8046580.htmlhttps://blog.csdn.net/xiaouncle/article/detail…

BookStack开源免费知识库docker-compose部署

BookStack&#xff08;书栈&#xff09;是一个功能强大且易于使用的开源知识管理平台&#xff0c;适用于个人、团队或企业的文档协作和知识共享。 一、BookStack特点 简单易用&#xff1a;BookStack提供了一个直观的用户界面&#xff0c;使用户能够轻松创建、编辑和组织文档多…

初学者必看!我的第一个Invideo人工智能文字生成视频

这是一个使用人工智能生成视频的在线平台。 主要功能包括: - 视频脚本自动生成:可以通过输入主题,由AI自动生成视频故事剧本。 - 人声合成:支持上传脚本,AI会合成自然的人声进行朗读。 - 视频制作:有多种视频模板可选择,支持上传自己的素材,一键生成完整视频。 - 特效和增…

SpringCluod深入教程

1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#…

平衡二叉树(AVL树)C++

目录 AVL树的概念 AVL树的节点结构 AVL树的插入 更新平衡节点 代码实现 AVL树的旋转 左单旋 右单旋 左右双旋 右左双旋 AVL树的删除 AVL树的查找 AVL树的高度 AVL树的判定 AVL树的遍历 AVL树的概念 二叉排序&#xff08;搜索&#xff09;树&#xff0c;虽然可以…

vue2项目中表格的增删查改

我们在项目中经常会用到对于表格的增删查改操作&#xff0c;以下使用vue2elementui来实现表格的增删查改 表格的基本属性 基础表格如下:(其中需要注意的是当el-table元素中注入data对象数组后&#xff0c;在el-table-column中用prop属性来对应对象中的键名即可填入数据&#x…

Oracle创建控制列表ACL(Access Control List)

Oracle创建控制列表ACL&#xff08;Access Control List&#xff09; Oracle ACL简介一、先登陆163邮箱设置开启SMTP。二、Oracle ACL控制列表处理&#xff08;一&#xff09;创建ACL&#xff08;create_acl&#xff09;&#xff08;二&#xff09;添加ACL权限&#xff08;add_…

②matlab桌面和编辑器

目录 matlab编辑器练习 运行脚本 matlab编辑器练习 您可以通过点击灰色代码框在脚本中输入命令。 准备就绪后&#xff0c;您可以通过点击蓝色的提交按钮提交代码。 任务 在脚本中输入命令 r 3。 2.任务 在脚本中添加命令 x pi*r^2。 附加练习 当您在实时编辑器中完成…

MyBatis分页插件PageHelper的使用及MyBatis的特殊符号---详细介绍

一&#xff0c;分页的概念 分页是一种将大量数据或内容分割成多个页面以便逐页显示的方式。在分页中&#xff0c;数据被分割成一定数量的页&#xff0c;每页显示一部分数据或内容&#xff0c;用户可以通过翻页或跳分页是一种将大量数据或内容分割成多个页面以便逐页显示的方式。…

跨平台图表:ChartDirector for .NET 7.1 Crack

什么是新的 ChartDirector for .NET 7.0 支持跨平台使用&#xff0c;但仅限于 .NET 6。这是因为在 .NET 7 中&#xff0c;Microsoft 停止了用于非 Windows 使用的 .NET 图形库 System.Drawing.Common。由于 ChartDirector for .NET 7.0 依赖于该库&#xff0c;因此它不再支持 .…