文件描述符

1、文件 = 文件内容 + 属性(也是数据)
2、文件的所有操作,无外乎: 1、对内容 2、对属性
3、文件在磁盘上(硬件)上放着,我们访问文件,先写代码——编译——exe——运行——访问文件:本质是谁在访问文件呢?进程(需要通过接口访问【语言C、C++、Java】).
要向硬件写入,只有 操作系统有权利{通过驱动程序}。
普通用户、也想写入呢? 必须让OS提供接口。文件类的系统调用接口!
跨平台
比较难 语言上对接口做一下封装,为了让接口更好的使用。导致了不同的语言,有不同的语言级别的文件访问接口。

  • 如果语言不提供对文件的系统接口的封装,是不是所有的访问文件的操作,都必须直接使用OS的接口? 是的
  • 而用语言的客户,要不要访问文件呢?当然要
  • 一旦使用系统接口,编写所谓的文件代码,无法在其他平台中直接运行了不具备跨平台性!
    4、显示器是硬件么?printf向显示器打印,也是一种写入 和磁盘写入到文件没有区别。

**

什么叫做文件?

**

  • 站在系统的角度,能狗被input读取,或者output写出的设备就叫做文件!
  • 侠义上的文件:普通的磁盘文件。
  • 广义上的文件:显示器,键盘、网卡、声卡、显卡、磁盘、几乎所有的外设都有可以被称之为文件。

1、C接口

[LHL@VM-8-7-centos 105]$ cd lesson19
[LHL@VM-8-7-centos lesson19]$ ll
total 0
[LHL@VM-8-7-centos lesson19]$ touch myfile.c
[LHL@VM-8-7-centos lesson19]$ ll
total 0
-rw-rw-r-- 1 LHL LHL 0 Mar 11 15:26 myfile.c
[LHL@VM-8-7-centos lesson19]$ ls > makefile
[LHL@VM-8-7-centos lesson19]$ vim makefile
[LHL@VM-8-7-centos lesson19]$ cat makefile
myfile:myfile.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f myfile 

2、直接使用系统接口

  • 进程要访问文件,必须要先打开文件!
  • 一个进程可以打开多个文件,一般而言 进程:打开的文件 = 1:n 的
  • 文件要被访问,前提是加载到内存中,才能被直接访问!
  • 进程:打开的问价 = 1 :n 的 -> 如果是多个进程都要打开自己的文件呢?系统中会存在大量的被打开的文件!所以,OS要不要把如此之多的文件也管理起来呢? 先描述,在组织!!

推荐使用语言级别的文件调用接口。具有平台移植性。

文件:
磁盘文件(没有被打开)
内存文件(被进程在内存中打开)

文件描述符的本质是数组下标。

#include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 #include <sys/stat.h>
  5 #include <fcntl.h>
  6 
  7 int main()
  8 {
  9   close(0); 10   //这里的fd分配的规则是:最小的没有被占用的文件描述>    符                                                   
 11   int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUN    C,0666);             
 12   if(fd < 0)         
 13   {                  
 14     perror("open");  
 15     return 1;        
 16   }                  
 17   printf("fd:%d\n",fd);
 18   close(fd);         
 19   return 0;          
 20 }                    
~        

输出重定向的原理:本质是在操作系统内部更改fd对应的内容指向。
输出重定向代码:使用 dup2(oldfp,newfp);

[LHL@VM-8-7-centos lesson20]$ ./myfile aaaaaaaaaaaaaaaaa
[LHL@VM-8-7-centos lesson20]$ cat log.txt
aaaaaaaaaaaaaaaaa
[LHL@VM-8-7-centos lesson20]$ ./myfile aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbb
[LHL@VM-8-7-centos lesson20]$ cat log.txt
aaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbb
[LHL@VM-8-7-centos lesson20]$ ./myfile aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbcccc
[LHL@VM-8-7-centos lesson20]$ cat log.txt
aaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbcccc
[LHL@VM-8-7-centos lesson20]$ cat myfile.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main(int argc,char *argv[])
{
  if(argc != 2)
  {
    return 2;
  }
 // int fd  = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC);
  int fd  = open("log.txt",O_WRONLY | O_CREAT | O_APPEND);
  if(fd < 0)
  {
    perror("open");
    return 1;
  }
  dup2(fd,1);
  fprintf(stdout,"%s\n",argv[1]);  //stdou->1->显示器

  close(fd);
  return 0;
}
[LHL@VM-8-7-centos lesson20]$ 

如何使用C语言实现面向对象甚至是运行时多态?

3、分析系统接口的细节,引入fd(文件描述符)

如何理解一切皆为文件?
底层不同的硬件,一定对应不同的操作方法!
但是上面的设备都是外设,所以每一个设备的核心访问函数都是可以 read、write I/O
因此函数指针层面(驱动开发之上)以及之上所有的设备都可以看作文件
称之为 VFS (虚拟文件管理系统)

缓冲区
1、什么是缓冲区:就是一段内存空间(这个空间是谁提供的?
2、为什么要有缓冲区?
写透模式 ,WT 成本高 慢
缓冲区最大的意义:提高整机效率。
3、缓冲区在哪里?

  • 缓冲区的刷新策略:1、立即刷新 2、行刷新 3.满刷新(全缓冲)
  • 绝对不是操作系统提供的。C标准库给我们提供的用户级缓冲区。
  • C语言中

myshell 简易的shell

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

#define NUM 1024
#define SIZE 32
#define SEP " "

//保存完整的命令行字符串
char cmd_line[NUM];

//保存打散之后的命令行字符串
char *g_argv[SIZE];

// 写一个环境变量的buffer,用来测试
char g_myval[64];

// shell 运行原理 : 通过让子进程执行命令,父进程等待&&解析命令
int main()
{
    extern char**environ;
    //0. 命令行解释器,一定是一个常驻内存的进程,不退出
    while(1)
    {
        //1. 打印出提示信息 [whb@localhost myshell]# 
        printf("[root@localhost myshell]# ");
        fflush(stdout);
        memset(cmd_line, '\0', sizeof cmd_line);
        //2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
        if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
        {
            continue;
        }
        cmd_line[strlen(cmd_line)-1] = '\0';
        //"ls -a -l -i\n\0"
        //printf("echo: %s\n", cmd_line);
        //3. 命令行字符串解析:"ls -a -l -i" -> "ls" "-a" "-i"
        // export myval=105
        g_argv[0] = strtok(cmd_line, SEP); //第一次调用,要传入原始字符串
        int index = 1;
        if(strcmp(g_argv[0], "ls") == 0)
        {
            g_argv[index++] = "--color=auto";
        }
        if(strcmp(g_argv[0], "ll") == 0)
        {
            g_argv[0] = "ls";
            g_argv[index++] = "-l";
            g_argv[index++] = "--color=auto";
        }
        //?
        while(g_argv[index++] = strtok(NULL, SEP)); //第二次,如果还要解析原始字符串,传入NULL
        if(strcmp(g_argv[0], "export") == 0 && g_argv[1] != NULL)
        {
            strcpy(g_myval, g_argv[1]);
            int ret = putenv(g_myval);
            if(ret == 0) printf("%s export success\n", g_argv[1]);
            //for(int i = 0; environ[i]; i++)
            //    printf("%d: %s\n", i, environ[i]);
            continue;
        }

        //for debug
        //for(index = 0; g_argv[index]; index++)
        //    printf("g_argv[%d]: %s\n", index, g_argv[index]);
        //4.内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令
        //内建命令本质其实就是shell中的一个函数调用
        if(strcmp(g_argv[0], "cd") == 0) //not child execute, father execute
        {
            if(g_argv[1] != NULL) chdir(g_argv[1]); //cd path, cd ..

            continue;
        }
        //5. fork()
        pid_t id = fork();
        if(id == 0) //child
        {
            printf("下面功能让子进程进行的\n");
            printf("child, MYVAL: %s\n", getenv("MYVAL"));
            printf("child, PATH: %s\n", getenv("PATH"));
            //cd cmd , current child path
            //execvpe(g_argv[0], g_argv, environ); // ls -a -l -i
            //不是说好的程序替换会替换代码和数据吗??
            //环境变量相关的数据,会被替换吗??没有!
            execvp(g_argv[0], g_argv); // ls -a -l -i
            exit(1);
        }
        //father
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));
    }
}

一般的目前互联网工作,更偏向于业务。面向应用端,能不能给公司创造价值。

./myfile >ok.txt 2>err.txt 将正确的结果和报错信息分开打印到不同的文档中。错误重定向。
./myfile > log.txt 2>&1 所有内容都放到1中 将2的指向文件地址重定向到1指向的位置。

文件系统

背景知识:

  • 1、有没有被打开的文件呢?当然存在。在哪里?磁盘—磁盘级文件
  • 2、我们学习磁盘级别的文件,我们侧重点在哪里?
    单个文件角度——这个文件的属性是什么?
    站在系统角度——一共有多少个文件?各自属性在哪里?如何快速找到?
    如何进行对磁盘文件进行分门别类的存储,用来支持更好的存取!
  • 3、磁盘文件 内存:掉电易失存储介质 磁盘:永久性存储介质 ssd,u盘,flash卡,光盘,磁带
  • 4、磁盘结构:
  • 磁盘的存储结构:
  • 为什么不以512为单位?1、太小了有可能会导致多次IO进而导致效率的降低 2、
[LHL@VM-8-7-centos lesson22]$ ln testLink2.txt hard.link
ln: failed to create hard link ‘hard.link’: File exists
[LHL@VM-8-7-centos lesson22]$ ln testLink2.txt hard.link
ln: failed to create hard link ‘hard.link’: File exists
[LHL@VM-8-7-centos lesson22]$ rm hard.link
[LHL@VM-8-7-centos lesson22]$ ln testLink2.txt hard.link
[LHL@VM-8-7-centos lesson22]$ ls -li
total 8
1051633 drwxrwxr-x 2 LHL LHL 4096 Mar 15 18:34 dir
1051635 -rw-rw-r-- 2 LHL LHL    0 Mar 15 18:35 hard.link
1051637 lrwxrwxrwx 1 LHL LHL   12 Mar 15 18:37 soft.link -> testLink.txt
1051634 -rw-rw-r-- 1 LHL LHL    0 Mar 15 18:35 testLink1.txt
1051635 -rw-rw-r-- 2 LHL LHL    0 Mar 15 18:35 testLink2.txt
1051636 -rw-rw-r-- 1 LHL LHL    0 Mar 15 18:35 testLink3.txt
1051632 -rw-rw-r-- 1 LHL LHL   11 Mar 15 18:33 testLink.txt
[LHL@VM-8-7-centos lesson22]$ 

在你的命令输出中,你尝试通过 ln 命令为 testLink2.txt 创建一个硬链接叫做 hard.link。然而,命令失败了,并显示错误信息:“ln: failed to create hard link ‘hard.link’: File exists”。这意味着 hard.link 这个名称的文件或链接已经存在于当前目录中。

错误的根源在于你的命令尝试创建一个硬链接的名称(hard.link)与已存在的一个符号链接(软链接)的名称相同。在UNIX和Linux文件系统中,硬链接和软链接都使用文件名作为标识符,所以任何类型的链接都不能有相同的名称。

要解决这个问题,你有几个选择:

删除已存在的链接,然后重新尝试:
如果你确定不再需要名为 hard.link 的软链接,可以首先删除它,然后再次尝试创建硬链接。

bash
Copy code
rm hard.link
ln testLink2.txt hard.link
使用不同的名称创建硬链接:
如果你想保留现有的软链接,可以选择一个不同的名称为你的硬链接。

bash
Copy code
ln testLink2.txt new_hard_link_name

理解硬链接与软链接的区别:

硬链接:硬链接是文件系统中另一个指向相同磁盘数据(inode)的指针。硬链接与原始文件功能上相同,删除任一链接,文件的内容依旧存在,直到所有的链接都被删除。
软链接(符号链接):软链接相当于是对另一个文件的快捷方式或引用,它包含的是另一个文件的路径名。如果原始文件被删除,软链接将失效。相当于Windows的快捷方式。
记住,文件名是指向inode的链接,硬链接就是创建另一个文件名指向同一个inode。由于 hard.link 已经存在,系统不允许你创建一个新的指向不同内容的链接(无论是硬链接还是软链接)而不先删除或重命名现有的链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lihongli000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值