Linux | 文件操作的系统调用 文件表

目录

一、文件描述符、Linux操作文件的系统调用

1.C语言中对文件的操作

2.Linux中对文件的操作

(1)打开文件 open()  系统调用(实现在内核中)

 (2)向文件中写入数据   write()

(3)读取一个文件 read()

(4)关闭文件  close() 

3. 实际应用

(1)直接使用

 (2)实现对任意文件的cp拷贝功能(输入源文件名和目的文件名)

 (3)fork复制文件描述符~父子进程共享文件偏移量

二、文件表的概念

1. 文件表的概念及理解

【举例】父、子进程同时对文件内容进行读操作并输出(2种情况)

 2. printf()的输出和键盘的输入底层原理

【举例】使用write()向屏幕上写数据

【举例】输出什么?  BAA

【举例】调用read()从键盘读入数据并打印(键盘的文件描述符为0)

 3. 库函数和系统调用的区别


一、文件描述符、Linux操作文件的系统调用

1.C语言中对文件的操作

 对于文件的管理:由操作系统~文件系统进行。

文件操作的系统调用 open read write close (系统调用:实现在内核中【用户态->内核态】“陷入内核”

C语言操作文件的库函数 fopen fread fwrite fclose (C语言fopen库函数的执行底层是调用Linux系统调用open();printf()库函数底层是调用write()系统调用实现的

2.Linux中对文件的操作

文件描述符fd:唯一描述该文件。(类似学号是学生的标志)

(1)打开文件 open()  系统调用(实现在内核中)

open()的返回值为整型的文件描述符

若文件存在:open() //文件名,打开方式:r,w

若文件不存在:open() //文件名,打开方式:r,w|creat,设置文件权限

参数flags为标志位:O_WRONLY 只写打开;  O_RDONLY 只读打开;O_RDWR 读写方式打开; O_CREAT 文件不存在则创建 ;O_APPEND 文件末尾追加 ;O_TRUNC 清空文件,重新写入。

参数mode为打开文件时文件不存在需要重建文件设置新文件的访问权限(文件已经创建好时权限已规定且无法修改)。

 (2)向文件中写入数据   write()

 

 返回值为实际写入的字节数。

参数fd为open的返回值(文件描述符),从buf指针指向位置开始向文件中写入buf指针指向内容的count个字节。

(3)读取一个文件 read()

 返回值为实际读取的字节数。若read()返回值为0,表示已读到文件末尾!

参数fd为open的返回值(文件描述符),从文件中向buf指针指向位置读入count个字节。

注意:存在文件偏移量,当已经读取10字节后,再进行读取,则会从已读入的字节后开始读入。

(4)关闭文件  close() 

 每次执行完文件操作别忘记关闭文件!!!

3. 实际应用

(1)直接使用

 

 (2)实现对任意文件的cp拷贝功能(输入源文件名和目的文件名)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
//read返回值==0~读到末尾

int main(int argc, char* argv[])
{
    if(argc!=3)//argv[0]=./mycp  argv[1]=源文件名  argv[2]=目的文件名
    {
        printf("argc err\n");
        exit(1);
    }
    char *s_name = argv[1];
    char *s_newname=argv[2];
    int fd1=open(s_name,O_RDONLY);
    if(fd1==-1)
    {
        printf("File:%s not exist\n",s_name);
        exit(1);
    }

    int fd2=open(s_newname,O_WRONLY|O_CREAT,0600);
    if(fd2==-1)
    {
        printf("Cerate File:%s error\n", s_newname);
        exit(1);
    }

    char buff[128] = {0};
    int num = 0;
    while ((num=read(fd1,buff,128))>0)
    {
        write(fd2, buff, num);//由于不确定每次读128个,所以每次写入读到的num个
    }

    close(fd1);
    close(fd2);

    exit(0);
}

 (3)fork复制文件描述符~父子进程共享文件偏移量

先open再fork:父子进程共享文件偏移量;先fork后open:文件偏移量不共享。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

int main()
{
    int fd = open("a.txt", O_RDONLY);
    if(fd==-1)
    {
        printf("open file error\n");
        exit(1);
    }
    
    //fork
    pid_t pid = fork();
    if(pid==-1)
    {
        printf("fork error\n");
        exit(1);
    }
    if(pid==0)//child  先open再fork:父子进程共享文件偏移量;先fork后open:文件偏移量不共享
    {
        char buff[32] = {0};
        read(fd, buff, 1);
        printf("child buff=%s\n", buff);
        sleep(1);
        read(fd, buff, 1);
        printf("child buff=%s\n", buff);
    }
    else//parent
    {
        char buff[32] = {0};
        read(fd, buff, 1);
        printf("parent buff=%s\n", buff);
        sleep(1);
        read(fd, buff, 1);
        printf("parent buff=%s\n", buff);
    }
    close(fd);
    exit(0);
}

对于a.txt(内容为abcdefg),运行结果为:

二、文件表的概念

1. 文件表的概念及理解

C语言中:

标准输入(文件)    键盘     File*    stdin  文件描述符fd=0

标准输出                   屏幕     File*    stdout  文件描述符fd=1

标准错误输出            屏幕     File*    stderr  文件描述符fd=2

 Linux中:

PCB中包含文件表(左边一栏文件表的下标代表文件描述符>=0,右边一栏对应打开的文件),关闭文件后文件描述符对应的文件消失,对于接下来打开的文件:描述符总选择最小且未被使用的

【举例】父、子进程同时对文件内容进行读操作并输出(2种情况)

若文件为a.txt(内容:abcdef):

1) 先打开文件再fork,则输出a,b,c,d;(父、子进程文件偏移量共享!父进程的开的文件(文件描述符)会复制到子进程,父子进程共享该文件

 当父进程执行结束关闭文件close()时,其与struct file的联系断开,r.cout变为1,但子进程仍可以对文件进行操作。故若要避免此情况,应该在父、子进程中均执行close()关闭文件,共执行两次。

(2)fork()后打开文件,则输出a,a,b,b(文件偏移量不共享)

 2. printf()的输出和键盘的输入底层原理

printf()最终调用write()输出在屏幕终端上,write()为系统调用,内核实现。printf()攒够数据到缓冲区后便由用户态->内核态调用write()全部打印。

【举例】使用write()向屏幕上写数据

写到屏幕即stdout,调用write参数文件描述符为1

 此处的write(1,"hello",5); 就等价于printf("hello");

【举例】输出什么?  BAA

 解释:父进程先将A放在缓冲区,父进程打印出B,fork()连同缓冲区(A)一同复制给子进程,程序运行结束再调用write()刷新缓冲区输出AA。 

【举例】调用read()从键盘读入数据并打印(键盘的文件描述符为0)

 3. 库函数和系统调用的区别

库函数:printf(),strlen(),还包括自己实现的函数add()等。库函数的实现在该库中。

系统调用:getpid()等。由内核实现,为内核代码的一部分。系统调用本质:陷入内核,传递系统调用号和参数,执行正确的系统调用函数,把返回值带回用户空间。

man 操作手册:1 命令   2 系统调用    3 库函数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值