0
点赞
收藏
分享

微信扫一扫

游戏联运系统|那些你必须了解的专业术语!

何以至千里 2023-05-23 阅读 105

open:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

pathname:要打开或创建的目标文件

flags:打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行"或"运算( '|' )

参数:

  • O_RDONLY:只读打开
  • O_WRONLY:只写打开
  • O_RDWR:读,写打开。这三个参数必定指定一个且只能指定一个
  • O_CREAT:若文件不存在,则创建它,需要使用mode选项,来指名新文件的访问权限
  • O_APPEND:追加写

返回值:成功就返回新打开的文件描述符,失败就返回-1

使用:open函数具体使用哪个分场景而定,如果目标文件不存在,需要open创建,就要使用三个参数,并且设置新创建文件的权限。

int open(pathname,O_CREAT,0666);//文件不存在,创建它并设置权限为0666

在学习返回值之前,先了解一下系统调用和库函数。

  • 像fopen,fclose,fread,fwrite这些都是C标准库中的函数 ,称之为库函数
  • 而open,close,read,write,lseek,这些都是OS提供的系统调用

 

 所以可以认为f#系列的函数,都是队系统调用函数进行了封装,方便进行二次开发

 


 

通过上面的open函数就可以知道,文件描述符fd就是一个小整数

0&1&2:

在Linux下,默认会有三个缺省打开的文件描述符,分别是标准输入0,标准输出1,标准错误2

0对应的是键盘,1和2对应的是显示器,即0是从键盘读入,1和2是像显示器输出。

 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
char buf[1024];
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0){
buf[s] = 0;
write(1, buf, strlen(buf));
write(2, buf, strlen(buf));
}
return 0;
}

上面代码就是利用系统调用接口write像显示器输出buf中的内容,用read从键盘上读取内容保存到数组buf中. 

 

 总结:文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中创建相应的数据结构来描述文件,于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files,指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该指针数组的下标。所以只要知道文件描述符,就可以找到对应的文件.

 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}

 最后输出的答案是" fd: 3"

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
close(0);
//close(2);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}

输出的是"fd: 0"。

可以得出结论:文件描述符的分配规则:在file_struct数组中,找到当前没有被使用的最小的下标,作为新的文件描述符


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
close(1);
int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
fflush(stdout);
close(fd);
exit(0);
}

 这时候我们发现本来应该输出到显示器上的内容,输出到了文件myfile中,其中fd = 1.这种输出现象叫做重定向。常见的重定向有>,>>,<

一张图了解重定向本质:

 


函数原型:

#include <unistd.h>
int dup2(int oldfd, int newfd);

dup系统调用分配的文件描述符是由系统分配的,遵循文件描述符的分配原则,并不能指定一个文件描述符,这是dup的一个缺陷,而dup2就很好的解决了这个问题

oldfd:需要被复制的文件描述符

newfd:指定一个文件描述符(需要指定一个当前进程没有使用到的文件描述符)

返回值:成功时返回一个新的文件描述符,也就是newfd;失败就返回-1 

示例:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("./log", O_CREAT | O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
close(1);
dup2(fd, 1);
for (;;) {
char buf[1024] = {0};
ssize_t read_size = read(0, buf, sizeof(buf) - 1);
if (read_size < 0) {
perror("read");
break;
}
printf("%s", buf);
fflush(stdout);
}
return 0;
}

 跟上面的代码一个效果。刚开始创建文件的时候,根据文件描述符分配原则,获得的fd应该为3,

这个时候调用dup2(fd,1)将fd的文件描述符改成1,并断开原先的标准输出,如上述重定向图一样。


因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。所以C库当中的FILE结构体内部,必定封装了fd。

借由下面一段代码来理解:

#include <stdio.h>
#include <string.h>
int main()
{
const char *msg0="hello printf\n";
const char *msg1="hello fwrite\n";
const char *msg2="hello write\n";
printf("%s", msg0);
fwrite(msg1, strlen(msg0), 1, stdout);
write(1, msg2, strlen(msg2));

fork();
return 0;
}

运行结果:

但是如果对文件进行输出重定向的话。./test > file 则文件file中会有

可以发现printf和fwrite都输出了两次,这两个都是库函数,而write只输出了一次,write为系统调用

综上:printf fwite库函数会自带缓冲区,而write系统调用没有带缓冲区,另外,我们这里的缓冲区都是用户级的缓冲区,作用就是提升整机性能,OS也会提供相关内核级缓冲区。

那这个用户级缓冲区由谁提供?

显然是C标准库提供,上述中printf和fwrite都是库函数,write是系统调用,库函数在系统调用的上层,是对系统调用的封装,但是write没有缓冲区,而printf和fwrite有缓冲区,说明缓冲区是在封装的时候加上的,也就是由C标准库提供的。 


在linux下使用指令ls -l

每行包含7列:

  •  模式
  • 硬连接数
  • 文件所有者
  • 大小
  • 最后修改时间
  • 文件名

inode:

为了解释清楚inode,先简单了解一下文件系统

磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,不可以更改。下图中的启动快(Boot Block)的大小是可以确定的

 

将属性和数据分开存放的想法看起来很简单,看下图。

 


硬链接 :

 特点:

  • 具有相同inode节点号的多个文件互为硬链接 文件
  • 删除硬链接 文件或者删除源文件任意之一,文件实体并未被删除
  • 只有删除了源文件和所有对应的硬连接文件,文件实体才会被删除
  • 硬链接 ​​​​​​文件是文件的另一个入口
  • 可以用过给文件设置硬连接文件来防止重要文件被误删
  • 可以通过ls -i看到index;
  • 硬链接文件是普通文件,可以用rm删除
  • 对于静态文件(没有进程正在调用),当硬链接数为0时文件就被删除。注意:如果有进程正在调用,则无法删除或者及时文件名被删除空间也不会释放

 

软链接 :

特点:

  • 软链接 类似windows系统的快捷方式
  • 软链接里面存放点的是源文件的路径
  • 删除源文件,软链接依然存在,但无法访问源文件内容
  • 软链接失效时一般是白字红底闪烁
  • 创建软链接命令ln -s 源文件 软链接文件;
  • 软链接文件和源文件是不同的文件,稳健类型也不同,inode号也不同
  • 软链接的文件类型是"I",可以用rm删除
举报

相关推荐

0 条评论