Linux命令【四】文件+虚拟内存+常用系统函数

File*其实是一个结构体

  • 文件描述符FD:索引到对应的磁盘文件
  • 文件读写位置指针FP_POS,如果同时读写需要注意文件指针的位置
  • I/O缓冲区BUFFER:保存内存指针,默认大小是8kb,用于减小我们对硬盘操作的次数。因为我们对硬盘的操作是ms级别的,而我们电子设备的操作是ns级别的。
  • 刷新缓冲区到硬盘上:fflush、缓冲区已满、文件正常关闭、return main、exit main
  • Linux系统函数没有缓冲区,C库函数自带缓存

在Linux中,inode保存文件的属性,里面有一个结构体struct stat,其中记录了文件的各种信息,但是没有保存文件名。
文件名保存在denty(目录项)中,每一个文件名对应一个inode编号。每一个硬链接都是一个denty

以Linux32为系统为例:

  • 文件描述符:
    • Linux为每一个运行的程序分配0-4G的内存
    • 0-3G是用户区,3-4G是内核区,内核区不允许用户去访问
    • 文件描述符位于内核区中的PCB进程控制块中,0-1023,每个位置储存一个文件。0\1\2默认是打开的,分别是STDIN_FiLENO 、STDOUT_FILENO 、STDERR_FILENO,每打开一个新文件,会多储存一个文件描述符。是一个栈

查看文件格式:file 文件

虚拟地址

用户区:0-3G

  • 受保护的内存(0-4K)none指针指向这个位置
  • ELF段
    • .text 代码段,二进制机器指令,包含main函数、静态库
    • .rodata段 和.text一样都是ro(只读)权限,在链接的时候完成数据段合并
    • .data段 已经初始化的全局变量
    • .bss未初始化的全局变量,和.data段一样是rw(读写)权限
  • 堆空间:保存全局变量,用malloc或者new在堆上分配内存
  • 共享库: 动态库,对库的调用是相对的地址。
  • 栈空间:从上面开始分配内存,保存局部变量
  • 命令行参数:main函数的参数
  • 环境变量:env查看

CPU使用虚拟地址与物理空间映射的作用:

  • 方便编译器和操作系统安排程序的地址分布:程序可以使用一系列连续的虚拟地址访问内存中不连续的内存缓冲区
  • 方便进程之间的隔离:不同进程之间彼此隔离,一个进程中的代码无法更改正在另一项进程的物理内存
  • 方便OS使用内存:程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常为4KB)保存到此案文件。数据或代码页会根据需要在物理内存和磁盘之间移动

printf函数

printf函数
调用write函数将文件描述符传递
应用层运行write函数
系统调用sys_write()函数,从用户态转化为内核态
内核层设备驱动函数

常用的系统应用函数

man 章节号 需要查找的函数 // 查看Linux手册中的函数

open函数

int open(const char *pathname, int flags);// The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY,  or O_RDWR.  These request opening the file read-only, write-only,or read/write, respectively.int open(const char *pathname, int flags, mode_t mode);
//mode:给创建文件设定访问权限

返回一个文件描述符,-1意思是发生了错误,errno会被赋予错误信息,使用需要包含errno.h

错误宏定义的位置:
第1-34个错误:usr/incclude/asm-generic/errno-base.h
第35-133个错误:/usr/include/asm-generic/errno.h

void perror(const char *s)用来将上一个函数发生错与原因输出到标准设备

编写函数的时候可以使用章节+ shift+k查看函数的man文档

例如:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>	//open的头文件
#include<unistd.h>	//close的头文件
#include<stdlib.h>	//exit的头文件
#include<stdio.h>	//perror的头文件
int main()
{int fd;	//用于保存文件描述符fd = open("main.c",O_RDWR);if(fd==-1){perror("open file");exit(1);}//创建新文件fd = open("newfile.c",O_RDWR | O_CREAT,777);//实际上文件的属性是775,因为本地有一个掩码,给定的权限将会和掩码有一个取反按位与的操作,实际上相当于减法//nmask获取本地掩码printf("新文件的文件描述符:%d\n",fd);//关闭文件int ret = close(fd);if(ret==-1){perror("close file");exit(1);}elseprintf("ret=%d\n",ret);return 0;
}

获取本地掩码:umask
修改本地掩码:umask xxxx
O_CREAT需要将掩码取反再将权限按位与

通过O_CREAT 与O_EXCL和起来使用判断文件是否已经存在,例如:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>	//open的头文件
#include<unistd.h>	//close的头文件
#include<stdlib.h>	//exit的头文件
#include<stdio.h>	//perror的头文件
int main()
{int fd;	//用于保存文件描述符
/*fd = open("main.c",O_RDWR);if(fd==-1){perror("open file");exit(1);}//创建新文件fd = open("newfile.c",O_RDWR | O_CREAT,777);//实际上文件的属性是775,因为本地有一个掩码,给定的权限将会和掩码有一个取反按位与的操作,实际上相当于减法//nmask获取本地掩码printf("新文件的文件描述符:%d\n",fd);
*/fd = open("myhelloc.c",O_RDWR|O_CREAT|O_EXCL , 777);if(fd==-1){perror("open file");exit(1);}
//关闭文件int ret = close(fd);if(ret==-1){perror("close file");exit(1);}elseprintf("ret=%d\n",ret);return 0;
}

文件清空、截断为0O_TRUNC

一定要注意对返回值做一个判断,这样出错的时候就能知道哪里出错。

read()

 #include <unistd.h>ssize_t read(int fd, void *buf, size_t count);

返回值:

  • -1 读文件失败,设置errno
  • 0文件读取了
  • x 读取了x个字符

write()

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

lseek()

#include <sys/types.h>#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
whence as follows:SEEK_SETThe file offset is set to offset bytes.SEEK_CURThe file offset is set to its current location plus offset bytes.SEEK_ENDThe file offset is set to the size of the file plus offset bytes.

使用举例:将一个文件的内容拷贝到另一个文件

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>	//Open
#include<unistd.h>	//Close
#include<stdlib.h>	//exit
#include<stdio.h>	//perror
#include<string.h>
#define MAXN 1005
char buffer[MAXN];	//缓冲区
int fd_in,fd_out;	//用于保存文件描述符void Open()
{fd_in=open("file_in",O_RDONLY);if(fd_in == -1){perror("Open fin:");exit(1);}//fd_out=open("file_out",O_WRONLY | O_CREAT | O_EXCL,0777);fd_out=open("file_out",O_WRONLY | O_CREAT,0644);if(fd_out == -1){perror("Open fout:");exit(1);}
}void Close()
{int ret=close(fd_in);if(ret==-1){perror("Close fin");exit(1);}if(ret==-1){perror("Close fout");exit(1);}
}void Work()
{int cnt=read(fd_in,buffer,MAXN);if(-1==cnt){printf("读取文件失败");}while(cnt)	//没有读取到文件末尾{write(fd_out,buffer,cnt);cnt=read(fd_in,buffer,MAXN);}
}	
int main()
{Open();Work();Close();
}

经验:

  • open函数如果使用O_CREAT参数,则需要指定使用权限(八进制数字,需要在权限前面加0),如果只使用O_CREATO_RDWR参数配合,如果文件已经存在就会打开之前的文件,不会创建新文件,如果再配合O_EXCL参数,那么如果已经存在文件就会报错。
  • 文件的实际权限是指定权限减去掩码
  • 不要眼高手低,即使看起来比较简单的东西还是需要多动手实践,才能发现自己的问题

lseek

 #include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
lseek()  repositions the file offset of the open file description associated
with the file descriptor fd to the argument offset according to  the  direc‐
tive whence as follows:SEEK_SETThe file offset is set to offset bytes.SEEK_CURThe file offset is set to its current location plus offset bytes.SEEK_ENDThe file offset is set to the size of the file plus offset bytes.
  • 获取文件长度ret=lseek(fd,0,SEEK_END)
  • 文件拓展:只能向后拓展文件,不能向前
int ret=lseek(fd,2000,SEEK_END);
//文件拓展需要最后做一次写操作,随便写一点东西就可以
//得到一个空洞文件,先得到预定大小的文件然后使用多线程操作
write(fd,"a",1);

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

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

相关文章

Python3列表

操作&#xff1a;索引、切片、加、乘、检查成员、确定序列长度、确定最大最小元素 定义&#xff1a; 列表名 [元素]下标列表名[x] 截取:列表名[x:y] 更新&#xff1a; list[x]y 或者使用append()方法添加列表项删除&#xff1a; del list[x]常用操作&#xff1a; 截取与…

Linux惊群效应详解(最详细的了吧)

https://blog.csdn.net/lyztyycode/article/details/78648798?locationNum6&fps1 linux惊群效应详细的介绍什么是惊群&#xff0c;惊群在线程和进程中的具体表现&#xff0c;惊群的系统消耗和惊群的处理方法。1、惊群效应是什么&#xff1f;惊群效应也有人叫做雷鸣群体效应…

epoll原理详解(最清晰)

https://blog.csdn.net/lyztyycode/article/details/79491419我只是把内容搬运过来做个记录&#xff0c;方便自己以后回头看。第一部分&#xff1a;select和epoll的任务关键词&#xff1a;应用程序 文件句柄 用户态 内核态 监控者要比较epoll相比较select高效在什么地方&#x…

Linux命令【五】系统函数

系统文件函数 stat函数 指针如果没有const一般表示传出参数&#xff0c;如果加const表示传入参数 struct stat dev_t st_dev文件设备编号ino_t st_ino节点 inode号是唯一的&#xff0c;每个inode节点的大小一般是128字节活着256字节&#xff0c;一般文件每2KB就设置一个ino…

生产者-消费者模型的两种实现方式

https://www.cnblogs.com/caolicangzhu/p/7086176.html本文主要来总结生产者-消费者模型的代码实现,至于其原理,请大家自行百度. 一、基于链表的生产-消费模型(条件变量)我们以链表为例,生产者进行头部插入,消费者进行头部删除,因此,先将链表相关操作封装为LinkList.h,具体代码…

Linux系统【一】CPU+MMU+fork函数创建进程

切板中的内容输出到文件### 进程相关概念 程序&#xff1a;编译好的二进制文件&#xff0c;在磁盘上&#xff0c;不占用系统资源&#xff08;不包括磁盘&#xff09;。&#xff08;剧本&#xff09; 进程&#xff1a;占用系统资源&#xff0c;是程序的一次运行。&#xff08;戏…

Ubuntu卸载软件

用过使用dpkg软件管理工具得到所有已经安装的软件&#xff0c;如果不清楚软件的全名可以使用grep命令进行查找 然后再使用sudo apt-get remove --purge 软件名卸载软件&#xff08;--purge参数会删除配置文件&#xff0c;删的干净一些&#xff09; 例如&#xff1a;

一个重要且实用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因为笔者之前的文章里面有错误&#xff0c;今天发现&#xff0c;立马做个修改。在下面我的一段关于sigchld信号相对于直接调用wait函数的好处时&#xff0c;我说调用wait函数要一直检测子进程是否执行完…

数据结构实验之链表七:单链表中重复元素的删除

https://blog.csdn.net/blessingxry/article/details/794455111.知识点&#xff1a;逆序建立链表&#xff0b;节点删除 2.题意&#xff1a;按照数据输入的相反顺序&#xff08;逆位序&#xff09;建立一个单链表&#xff0c;并将单链表中重复的元素删除&#xff08;值相同的元素…

Python3函数和代码复用

函数的定义 def 函数名([参数列表]):注释函数体注意事项 函数形参不需要声明类型&#xff0c;可以使用return语句在结束函数执行的同时返回任意类型的值&#xff0c;函数返回值类型与return语句返回表达式i的类型一致 即使该函数不需要接受任何参数&#xff0c;也必须保留一堆…

一文说尽C++赋值运算符重载函数(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html在前面&#xff1a;关于C的赋值运算符重载函数(operator)&#xff0c;网络以及各种教材上都有很多介绍&#xff0c;但可惜的是&#xff0c;内容大多雷同且不全面。面对这一局面&#xff0c;在下在整合各种资源及融入个人理解的基…

Python a和a[:]的区别

简单来讲a[:]是深复制&#xff0c;a是浅复制&#xff0c;相当于赋值a的话是赋值了指针&#xff0c;赋值a[:]相当于复制了a对应的那段空间 例如&#xff1a; a [1,1,1,1,1,1]for x in a:if x1:a.remove(x)print(a)运行结果&#xff1a; remove操作是移除序列中第一个x元素。…

约瑟夫环(c语言程序完整版)

https://blog.csdn.net/m_hahahaha1994/article/details/51742453约瑟夫环&#xff08;约瑟夫问题&#xff09;是一个数学的应用问题&#xff1a;已知n个人&#xff08;以编号1&#xff0c;2&#xff0c;3…n分别表示&#xff09;围坐在一张圆桌周围。从编号为k的人开始报数&am…

Linux系统【二】exec族函数及应用

文件描述符 文件描述符表是一个指针数组&#xff0c;文件描述符是一个整数。 文件描述符表对应的指针是一个结构体&#xff0c;名字为file_struct&#xff0c;里面保存的是已经打开文件的信息 需要注意的是父子进程之间读时共享&#xff0c;写时复制的原则是针对物理地址而言…

白话C++系列(27) -- RTTI:运行时类型识别

http://www.cnblogs.com/kkdd-2013/p/5601783.htmlRTTI—运行时类型识别 RTTI&#xff1a;Run-Time Type Identification。 那么RTTI如何来体现呢&#xff1f;这就要涉及到typeid和dynamic_cast这两个知识点了。为了更好的去理解&#xff0c;那么我们就通过一个例子来说明。这个…

使用头文件的原因和规范

原因 通过头文件来调用库功能。在很多场合&#xff0c;源代码不便&#xff08;或不准&#xff09;向用户公布&#xff0c;只 要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库 功能&#xff0c;而不必关心接口怎么实现的。编译器会从库中提取相应…

转圈踢人问题

https://www.cnblogs.com/lanxuezaipiao/p/3339603.html 有N个人围一圈依次报数&#xff0c;数到3的倍数的人出列&#xff0c;问当只剩一个人时他原来的位子在哪里&#xff1f; 解答&#xff1a;经典的转圈踢人问题&#xff0c;好吧专业一点&#xff0c;约瑟夫环问题&#xff0…

Linux系统【三】回收子进程

孤儿进程 父进程先于子进程结束&#xff0c;则子进程成为孤儿进程&#xff0c;子进程的父进程成为init进程&#xff0c;则称init进程领养孤儿进程。现在好像是用户进程中的system进程。 僵尸进程 进程终止&#xff0c;父进程不进行回收&#xff0c;自己成残留资源(PCB)存放在…

string类的基本实现

https://blog.csdn.net/qq_29503203/article/details/52265829在面试中面试官常常会让你写出string类的基本操作&#xff0c;比如&#xff1a;构造函数&#xff0c;析构函数&#xff0c;拷贝构造等等.下面是除此之外的一些操作&#xff0c;希望可以帮助你更好的理解string以便以…

Python3常用数据结构

Python3中有三种组合数据类型&#xff0c;分别为&#xff1a; 序列类型&#xff1a;字符串&#xff08;str&#xff09;、元组&#xff08;tuple&#xff09;、列表&#xff08;list&#xff09;集合类型&#xff1a;集合&#xff08;set&#xff09;映射类型&#xff1a;字典…