【Linux-Day7-文件操作,fork与malloc结合】

本文详细介绍了C语言中文件操作的基本步骤,涉及fopen、fclose、fread、fwrite等函数,并讨论了Linux中的文件操作系统调用,如open、read、write和close。还探讨了fork与文件操作、malloc内存分配的关系,以及父子进程共享资源的情况。
摘要由CSDN通过智能技术生成

操作文件的系统调用

(1)c 语言中文件操作回顾

C语言操作文件分为三步
1)打开文件
2)读写文件
3)关闭文件。

FILE fopen ( const char * filename, const char * mode );*

filename: 文件名,包括路径,如果不显式含有路径,则表示当前路径。

mode:文件打开模式,指出对该文件可进行的操作。常见的打开模式如 “r” 表示只读, “w” 表示只写,“rw” 表示读写,“a” 表示追加写入。

返回值: 打开成功,返回该文件对应的 FILE 类型的指针; 打开失败,返回 NULL。故需定义 FILE 类型的指针变量,保存该函数的返回值。

int fclose ( FILE * stream );

strem : 指向要关闭流对象的指针。

返回值:如果流被成功关闭,返回0值。失败是,返回EOF(-1)。

size_t fread(void buffer,size_t size,size_t count, FILE stream);

buffer:存放从文件中读取的数据; size:每个单元数据的字节数; count:总共读取多少个单元数据; stream:读取数据的文件指针。

返回值 :读取成功的单元数据个数,非常重要。如果这个值少于 count 则可以判断文件已经全部 读完

​ *size_t fwrite(const void*buffer,size_t size,size_t count,FILE stream);

buffer: 写入文件中的数据; size:每个单元数据的字节数; count:总共写入多少个单元数据; stream:写入的文件指针。

返回值:写入成功的单元数据个数。

等函数;

(2)Linux中与文件操作有关的系统调用

一、打开文件
  1. int open(const char***** pathname, int flags);//用于打开一个已存在的文件
  2. int *open(const char pathname, int flags,mode_t mode);//用于新建一个文件, 并设置访问权限

参数介绍

pathname:将要打开的文件路径和名称

flags : 打开标志,如 O_WRONLY 只写打开

​ O_RDONLY 只读打开

​ O_RDWR 读写方式打开

​ O_CREAT 文件不存在则创建

​ O_APPEND 文件末尾追加

​ O_TRUNC 清空文件,重新写入

mode: 权限 如:“0600” 0是八进制,6是 r+w -> 4+2 , 0 : 无权限
// ugo u:表示属主 g:表示同一组用户o:表示其他用户访问权限

返回值:为文件描述符二、读文件

二、读文件

**ssize_t read(int *fd, const void buf,size_t count);

参数介绍

fd 对应打开的文件描述符

buf 存放数据的空间

count 计划一次从文件中读多少字节数据

返回值:为实际读到的字节数

三、写文件

**ssize_t write(int *fd, const void buf,size_t count);

参数介绍

fd** 对应打开的文件描述符

buf 存放数据的空间

count 计划一次向文件中写多少字节数据

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

四、关闭文件

int **close(**int fd);

参数介绍

fd 要关闭的文件描述符

举例:

在这里插入图片描述

结果:

在这里插入图片描述

fd (文件描述符 )的值一定大于等于3,这是因为

操作系统为每一个进程维护了一个文件描述符表,该表的索引值都从从0开始的,其中0、1、2分别为标准输入、标准输出和标准错误输出的文件描述符

文件操作与fork()相结合

1.QS: 父进程先打开一个文件,fork 后子进程是否可以共享使用?

结论: 可以共享使用

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

int main() 
{ 
 char buff[128] = {0}; 
              //file.txt 内容为“BCDF” 
 int fd = open("file.txt",O_RDONLY); 
 pid_t pid = fork(); 
 assert( pid != -1 ); 
 if ( pid == 0 ) 
 { 
 read(fd,buff,1); 
 printf("child buff=%s\n",buff); 
 sleep(1); 
 read(fd,buff,1); 
 printf("child buff=%s\n",buff); 
} 
 else 
 { 
 read(fd,buff,1); 
 printf("parent buff=%s\n",buff); 
 sleep(1); 
 read(fd,buff,1); 
 printf("parent buff=%s\n",buff); 
 } 
    close(fd);
}

在这里插入图片描述

由于 fork 创建的子进程的 PCB 是拷贝父进程的,子进程的 PCB 中的文件表指向打开文件的指针只是拷贝了父进程 PCB 中的值,所以父子进程会共享父进程 fork 之前打开的所有文件描述符,所以父子进程不会对同一数据重复读取。

父子进程文件描述符指向同一个struct.file,其中的引用计数为2,为避免同一个文件多次关闭,只有当引用计数减一为0是才真正关闭文件。

2.先fork(),后打开文件

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

int main() 
{ 
 char buff[128] = {0}; 
 int fd;
 pid_t pid = fork(); 
 assert( pid != -1 ); 
 if ( pid == 0 ) 
 { 
 sleep(1); 
                  //file.txt 内容为“BCDF”
  fd = open("file.txt",O_RDONLY); 

  read(fd,buff,1);
 printf("child buff=%s\n",buff); 
  read(fd,buff,1); 
 printf("child buff=%s\n",buff); 
} 
 else 
 { 
 sleep(1); 
                  //file.txt 内容为“BCDF”
  fd = open("file.txt",O_RDONLY); 
  read(fd,buff,1);
 printf("parent buff=%s\n",buff); 
  read(fd,buff,1); 
 printf("parent buff=%s\n",buff); 
 } 
    close(fd);
}


分析:

malloc 申请内存问题

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main()
{
    char* p = '1';
    for( ; p!=NULL;)
   {
     p=(char*)malloc(1024*1024*1024);
   if(p != NULL) memset(p,0,1024*1024*1024);
   else
       printf("malloc error");
   sleep(3);
   } 
   exit(0);
}

有两种情况下会失败

1.剩余内存足够,但是没有满足条件的连续空间,将申请失败
2.申请空间大于物理内存空间+虚拟内存空间,那么申请空间将失败

代码中我们未进行free()操作,当可用内存不够malloc时,系统会自动杀死进程,然后回收该进程的占用的空间。

如图:

fork和malloc 结合

QS: fork()前malloc,父子进程是共享同一块堆区空间还是各自拥有一块?

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main()
{
    char* p=(char*)malloc(1024*1024*1024);
    if(p == NULL) printf("malloc error");
    pid_t pid = fork();
    if(pid == -1)
    {
        printf("error fork!\n");
    }
    if(pid == 0)
    {
        strcpy(p,"child\n");
        printf("child: %s",p);
    }
    else
    {
        strcpy(p,"parents\n");
        printf("parent: %s",p);
    }
   sleep(3);
    free(p);
   exit(0);
}

运行结果: 父子进程各自拥有一块堆区空间。这表明:父进程在堆区申请的空间,也会被子进程复制一份 在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值