day 3

本文详细讲解了标准输入输出流与文件I/O的基本概念,涉及fread/fwrite函数的使用,文件复制(cp)实现,以及进程管理、缓冲区原理和库函数的区分。通过实例演示了如何读写文件、定位文件指针和使用动态链接库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

复习:
文件IO
int fd=open(文件名,打开方式,文件权限)
文件描述符分配规则:当前尚未分配 最小非负整数
标准输入 输出 错误输出
键盘 0 屏幕 1 屏幕 2

ssize_ret = read(fd,buf,count)
write (fd,buf,count)
close(fd)

标准IO
FILE *
FILE *fp = fopen(文件名,打开方式)
fclose(fp)
char *pret = fgets(buf,size,fp) //9
fputs(buf,fp)
char ch = fgetc(fp)
fputc(ch,fp)

作业:
////////////////////////////////////////////////
#include<stdio.h>
int main()
{
//打开源文件
FILE *fp_r = fopen(“my.h”,“r”);
if(NULL==fp_r)
{
perror(“fp_r”);
return 0;
}

//创建并打开目标文件
FILE *fp_w = fopen("b.txt","w");
if(NULL==fp_w)
{
	perror("fp_w");
	fclose(fp_r);
	return 0;

}
char pret;
int ret;

while(1)
{
    //从源文件中读取一个字符
	pret = fgetc(fp_r); 
	if(EOF==pret)//说明读到文件结尾
	{
		break;
	}
    //将读到字符写入目标文件
	ret = fputc(pret,fp_w);
	if(EOF==ret)
	{
		perror("fputc");
		fclose(fp_r);
		fclose(fp_w);
		return 0;
	}
}
fclose(fp_r);
fclose(fp_w);

}

////////////////////////////////////////////////

一、标准IO续

1.按指定大小/按类型 读写
(1) size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:按指定大小读
从stream读取数据放到ptr 每次读size个字节 读nmemb次
返回值:成功返回实际读的次数nmemb 如果失败或到文件结尾 返回值<nmeb或==0 用feof判断是否到达文件结尾
//size_t unsigned int

//fread(buf,10,2,fp);
////////////////////////////
#include<stdio.h>
int main()
{
    FILE *fp = fopen("note","r");
    if(NULL==fp)
    {
        perror("fopen");
        return 0;
    }

    char buf[100]="\0";

    //读取文件fp中数据 存放到buf中 读取2次 每次读10个字节
    size_t ret = fread(buf,10,2,fp);
    if(ret!=2)//没有读够2次
    {
        //perror("fread");
        printf("read:%s\n",buf);
        
        fclose(fp);
        return 0;
    }

    printf("read:%s\n",buf);
    fclose(fp);
    return 0;

}

(2)size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:按指定大小写
将ptr的数据写到stream中  每次写size个字节  写nmemb次
返回值:成功返回实际写的次数nmemb  如果失败 返回值<nmeb或==0 

///////////////////////////////////////////////
#include<stdio.h>
int main()
{
    FILE *fp = fopen("note","w");
    if(NULL==fp)
    {
        perror("fopen");
        return 0;
    }

    char buf[100]="good good study";

    //将buf中数据 写入文件fp中  写1次 每次写10个字节
    size_t ret = fwrite(buf,10,1,fp);
    if(ret!=1)//没有写够1次
    {
        perror("fread");
        //printf("read:%s\n",buf);
        
        fclose(fp);
        return 0;
    }

    fclose(fp);
    return 0;

}
///////////////////////////////////////////////

int feof(FILE *stream);
功能:测试文件位置指针是否到达文件结尾
返回值:如果到达文件结尾 则返回真 否则返回假

//实例:读取整个文件内容
///////////////////////////
#include<stdio.h>
#include<strings.h>
int main()
{
FILE *fp = fopen(“my.h”,“r”);
if(NULL==fp)
{
perror(“fopen”);
return 0;
}

    char buf[100]="\0";

while(1)
{
	//清空缓存
	bzero(buf,sizeof(buf));
    
	//读取文件fp中数据 存放到buf中 读取2次 每次读10个字节
 size_t ret = fread(buf,10,2,fp);


	printf("%s",buf);
	//如果读到文件结尾 退出循环
	if(feof(fp))//如果返回值为真 说明到文件结尾
	{
		break;
	}
}

    fclose(fp);
    return 0;

}
/////////////////////////////////////////

练习:实现cp
/////////////////////////////////////////
#include<stdio.h>
#include<strings.h>
int main(int argc,cosnt char*argv[])//./mycp my.h dst
{
if(argc!=3)
{
printf("%s src dst\n",argv[0]);
return 0;
}

char buf[100]="\0";

//打开源文件
FILE *fp_src = fopen(argv[1],"r");
if(NULL==fp_src)
{
	perror("fopen-read");
	return 0;
}
//打开目标文件
FILE *fp_dst = fopen(argv[2],"w");
if(NULL==fp_dst)
{
	perror("fopen-dst");
	return 0;
}

while(!feof(fp_src))//说明没读到源文件结尾
{
	//将源文件fp_src内容读取sizeof(buf)个字节 读一次  存入buf中
	fread(buf,sizeof(buf),1,fp_src);
	

	fwrite(buf,sizeof(buf),1,fp_dst);
	bzero(buf,sizeof(buf));
}

fclose(fp_src);
fclose(fp_dst);
return 0;

}
/////////////////////////////////////////
3.
int fseek(FILE *stream, long offset, int whence);
功能:定位
参数2 3 同lseek

fseek(fp,-10,SEEK_END);//相对于文件结尾 向左偏移10个字节
fseek(fp,-10,SEEK_CUR);//相对于当前位置 向左偏移10个字节
fseek(fp,10,SEEK_SET);//相对于文件开头 向右偏移10个字节
////////////////////////////////////////
实例:
#include<stdio.h>

int main()
{
    FILE *fp = fopen("note","r");//goodstudy
    if(NULL==fp)
    {
        perror("fopen");
        return 0;
    }

	
	char read_buf[50]="\0";//读缓存  
	fread(read_buf,2,1,fp);//go   读取2个字节 读完后偏移2个字节
	printf("%s\n",read_buf);

	fseek(fp,2,SEEK_CUR);//相对当前位置 右偏移2个字节
	fread(read_buf,2,1,fp);//
	printf("%s\n",read_buf);//st 

	fseek(fp,-1,SEEK_CUR);//相对当前 左偏移1字节
	fread(read_buf,2,1,fp);//
	printf("%s\n",read_buf);//tu 

    fclose(fp);
    return 0;
}

/////////////////////////////////////////////////////////////////
实例:
#include<stdio.h>

int main()
{
    FILE *fp = fopen("note","w+");//goodstudy
    if(NULL==fp)
    {
        perror("fopen");
        return 0;
    }
	char read_buf[50]="\0";//读缓存  
	
	fwrite("goodstudy",9,1,fp);

	fseek(fp,-5,SEEK_END);
	printf("**%d\n",fgetc(fp));
//	printf("&&:%d\n",ftell(fp));

	fread(read_buf,2,1,fp);//
	printf("%s\n",read_buf);//st
	
    fclose(fp);
    return 0;

}
//////////////////////////////////////////////////////////////

void rewind(FILE *stream);
功能:将位置指针定位到文件起始位置
rewind(fp)等价于fseek(fp,0,SEEK_SET);

long ftell(FILE *stream);//%ld
功能:返回当前文件读写位置(测试当前光标位置离文件开头距离)

/////////////////////////////////////////
#include<stdio.h>

int main()
{
    FILE *fp = fopen("note","r");//goodstudy
    if(NULL==fp)
    {
        perror("fopen");
        return 0;
    }

	
	char read_buf[50]="\0";//读缓存  
	rewind(fp);//将文件位置指针定位到文件开头
	fread(read_buf,2,1,fp);//
	printf("%s\n",read_buf);//go 

	long n = ftell(fp);//测距离
	printf("%ld\n",n);

    fclose(fp);
    return 0;

}
////////////////////////////////////////////

二、库

  1. 什么是库
    库函数
    (1) 库函数为了实现某个功能而封装起来的API集合
    (2) 提供统一的编程接口,更加便于应用程序的移植

    库函数(linux系统会提供一系列的库函数,供使用者调用)
    这些函数都是经过测试的,如果某个功能函数系统提供了,我们尽量不要自己写
    本质上说是可执行的二进制代码,可被OS载人内存执行
    一般而言,库是别人编好的,成熟的,可复用的代码,我们使用是必须遵循接口标准

     库文件
     函数库 /lib  /usr/lib
    

2.理解
库有两种类型
1)动态链接库(运行时再去找库函数)
又叫共享库 , 在程序链接(动态库链接放入程序中),执行调用库函数时,加载该库, 可执行文件 小 ; 删除 原动态库, 程序有影响
linux中 .so windows中 .dll
优点:
1) 如果有多个程序用到一个dll, 节省内存,节省硬盘空间
2) 运行效率高(第二次运行不需要加载)
3) 升级方便(不需要修改应用程序)

2)静态库 (编译时会将库函数写到文件中)
使用静态库时, 必须在程序 编译时 就已经加载(拷贝)该库, 当前生成可执行文件 大;删除 原静态库, 对编译好的程序没有影响
linux中 .a      windows中  .lib

优点:
    如果库文件丢失,可执行文件仍然可执行

3.实现库
(1)实现静态库:(以空间换时间)在编译链接时 将库文件代码全部加入可执行文件中 生成的文件大 后缀名是.a
libxxx.a xxx是库名

使用归档工具ar将一系列目标文件集成到一起

 生成及使用过程:
	将函数的源代码生成目标文件(.o)
	gcc -c fun.c -o fun.o
	gcc -c fun1.c -o fun1.o
	
	创建静态库:静态库的名字必须lib开头 .a结尾
	ar crv libmyfun.a fun.o  fun1.o 
	
	使用静态库:
	gcc main.c -L. -lmyfun -o exe 
	./exe 
	
	-L 指定库所在的路径
	-l 指定库名 


 	
(2)实现动态库:(以时间换空间)程序执行到相关的函数时 才调用该函数库中的相应函数 因此动态库产生的可执行文件较小
	    前缀lib 后缀.so  libxxx.so.major.minor 
	    生成及使用过程: 
	    将函数的源代码生成目标文件(.o)
	    gcc -c fun.c -o fun.o
	    gcc -c fun1.c -o fun1.o
	
	    创建动态库:
	    gcc -shared -fPIC fun.o fun1.o -o libmyfun.so
 
	    使用动态库:
	    sudo  cp libmyfun.so /usr/lib //指定路径也不行 必须放这里
	    gcc main.c -lmyfun -o exe
	    ./exe

三、缓冲区
缓冲文件系统(高级磁盘IO)–标准io
非缓冲文件系统(低级磁盘IO)–文件io

缓存
用户空间缓存 --buff
内核空间缓存 —
库缓存 —

(1)行缓存 遇到回车或写满 会调用系统调用函数
#include<stdio.h>
//////////////////////////////
int main()
{

    printf("heihei~~~");//行缓存 遇到回车或写满 会刷新缓存区
    while(1);
}

//////////////////////////////    
int fflush(FILE *stream);
功能:刷新io缓存

//////////////////////////////
#include<stdio.h>

int main()
{

    printf("heihei~~~");
    fflush(stdout);//刷新缓存 stdout 标准输出
    while(1);
}
////////////////////////////// 

注意:
标准IO 中
标准输入  stdin 
标准输出  stdout 
标准错误输出 stderr

(2)无缓存
不对IO操作进行缓存,对流的读写可以立即操作实际文件

#include<stdio.h>

int main()
{
    fwrite("heihei",7,1,stderr);//标准错误输出 是没有缓存区
    while(1);
}

(3)全缓存:只有缓存写满 才调用系统调用函数

二、区别
总结:区别:
文件I/O和标准I/O的本质区别:
1)缓冲区:标准I/O函数接口在对文件进行操作时,首先操作缓存区,等待缓存区满足一定的条件时,然后再去执行系统调用,真正实现对文件的操作。 而文件I/O不操作任何缓存区,直接执行系统调用。

    2)系统开销:使用标准I/O可以减少系统调用的次数,提高系统效率。例如,将数据写入文件中,每次写入一个字符。采用文件I/O的函数接口,每调用一次函数写入字符就会产生一次系统调用。        而执行系统调用时,Linux必须从用户态切换到内核态,处理相应的请求,然后再返回到用户态,如果频繁地执行系统调用会增加系统的开销。

    3)执行效率:采用标准I/O的函数接口,每调用一次函数写入字符,并不着急将字符写入文件,而是放到缓存区保存,之后每一次写入字符都放到缓存区保存。直到缓存区满足刷新的条件(如写满)时,再一并将缓存区中的数据写入文件,执行一次系统调用完成此过程,这样便很大程度地减少了系统的调用次数,提高了执行效率。

三、进程

一、进程
1.进程:正在运行的程序 进程是程序的载体

2.进程与程序区别
程序是静态的 它是保存在磁盘上的指令的有序集合 没有执行的概念
进程是动态的 它是执行的过程 包括:创建 调度和消亡

程序: 是一个静态的概念。 
进程: 程序的执行过程。  

3.进程状态
就绪态
执行态
阻塞态
(1)就绪状态:进程已获得除CPU外的所有必要资源,只等待CPU时的状态。一个系统会将多个处于就绪状态的进程排成一个就绪队列。
(2)执行状态:进程已获CPU,正在执行。单处理机系统中,处于执行状态的进程只一个;多处理机系统中,有多个处于执行状态的进程。
(3)阻塞状态:正在执行的进程由于某种原因而暂时无法继续执行,便放弃处理机而处于暂停状态,即进程执行受阻。(这种状态又称等待状态或封锁状态)

进程是程序执行和资源分配的最小单位。

进程控制块PCB:
vim /usr/src/linux-headers-3.2.0-29/include/linux/sched.h //1227

进程的内存结构: linux 采用虚拟内存管理技术,使得每个进程都有独立的地址空间。

4.进程的模式:用户模式 内核模式

5.进程一生

出生:
    fork 
事业:exec(任务) 
消亡:
    自然消亡 }
    自杀      exit 
    他杀      kill 
    
收尸:父给子
     释放资源
     继承遗产
      报仇 
      
   父在 不收  
   
   僵尸进程:父进程没消亡 但不为子进程收尸  子进程是僵尸进程 避免僵尸进程       
   孤儿进程:父进程消亡 子进程还在运行 这时 子进程是孤儿进程 会被init进程领养并收尸

6.进程ID 是PID init进程是进程祖先 PID 是1
ps aux 查看所有用户所有进程详细信息
pstree 查看进程树
top 动态查看进程信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

encounter♌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值