复习:
文件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) 库函数为了实现某个功能而封装起来的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 动态查看进程信息