- 作业:在文件任意位置处插入数据
#include <stdio.h>
#include <string.h> //strerror()
#include <errno.h> //errno
#include <unistd.h> //write() read() sleep()
/*open()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PER_IO_BYTES 4096
int main(int argc,char *argv[])
{
int fd=-1;
char caFile[32]={'\0'};//将原来文件保存再重命名
strncpy(caFile,argv[1],sizeof(caFile));//将test.data里面的内容复制到caFile
int ret=-1;
strcat(caFile,".old");
ret=rename(argv[1],caFile);//将原来的文件重命名
if(-1==ret)
{
printf("rename error:%s\n",strerror(errno));//如果错误,打印错误信息
return -1;
}
int fdNew=-1;
fdNew=open(argv[1],O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);//写打开,访问权限
if(-1==fdNew)
{
printf("open error:%s\n",strerror(errno));
return -1;
}
int fdOld=-1;
fdOld=open(caFile,O_RDONLY);//读打开原来的文件
if(-1==fdOld)
{
printf("open error:%s\n",strerror(errno));
return -1;
}
off_t offset=0;//定义偏移量为5
printf("please input position:");
scanf("%ld",&offset);
char caBuf[PER_IO_BYTES]={'\0'};//初始化
int iLeft=offset;
int iReaded=0;
while(iLeft)//将指定位置前面的数据读出来
{
if(iLeft>=PER_IO_BYTES)
{
ret=read(fdOld,caBuf,PER_IO_BYTES);
}
else
{
ret=read(fdOld,caBuf,iLeft);
}
if(-1==ret)
{
printf("read error:%s\n",strerror(errno));
break;
}
iLeft-=ret;
ret=write(fdNew,caBuf,ret);
if(-1==ret)
{
printf("write error:%s\n",strerror(errno));
break;
}
}
//在制定的位置插入该数据
char *pData="$$$qqrhtewrywywruiepitrew$$$";
ret=write(fdNew,pData,strlen(pData));
if(-1==ret)
{
printf("write error:%s\n",strerror(errno));
return;
}
offset=lseek(fdOld,0,SEEK_CUR);
while(1)
{
ret=read(fdOld,caBuf,PER_IO_BYTES);
if(-1==ret)
{
printf("read error:%s\n",strerror(errno));
break;
}
else if(0==ret)
{
break;
}
ret=write(fdNew,caBuf,ret);
if(-1==ret)
{
printf("write error:%s\n",strerror(errno));
break;
}
}
close(fdNew);
close(fdOld);
ret=remove(caFile);
if(-1==ret)
{
printf("remove error:%s\n",strerror(errno));
return -1;
}
return 0;
}
//gcc lseek1.c
//./a.out test.data
//结果为:在第第四个位置插入数据:
//1234$$$qqrhtewrywywruiepitrew$$$567890abcdefghijklmn
ACCESS(测试)
- 测试文件是否存在
#include<unistd.h>
#include<stdio.h>//perror
//mode:
// F_OK:测试文件是否存在
// R_OK:测试用户是否对文件具有可读权限
// W_OK:测试用户是否对文件具有可写权限
// X_OK:测试用户是否对文件具有可执行权限
//测试用户对于指定的文件是否具有mode权限
//如果有,则函数返回0
//否则返回-1
//int access(const char *pathname, int mode);
int main(int argc,char *argv[])
{
int ret=-1;
ret=access(argv[1],F_OK);//测试文件是否存在
if(-1==ret)
{
perror("access");//如果错误,则会打印access:错误信息
return -1;
}
else if(0==ret)
{
printf("file exist\n");
}
return 0;
}
//./a.out test.data
- 测试文件是否有可读可写权限
#include<unistd.h>
#include<stdio.h>//perror
int main(int argc,char *argv[])
{
int ret=-1;
ret=access(argv[1],R_OK | W_OK);//测试文件是否有可读可写的权限
if(-1==ret)
{
perror("access");//如果错误,则会打印access:错误信息
return -1;
}
else if(0==ret)
{
printf("user has those permissions\n");
}
return 0;
}
//./a.out test.data
- 测试文件是否有可执行权限
#include<unistd.h>
#include<stdio.h>//perror
int main(int argc,char *argv[])
{
int ret=-1;
ret=access(argv[1],X_OK);//测试文件是否有可读可写的权限
if(-1==ret)
{
perror("access");//如果错误,则会打印access:错误信息
return -1;
}
else if(0==ret)
{
printf("user has those permissions\n");
}
return 0;
}
OPENDIR(打开目录)
- 打开一个文件目录
#include <stdio.h>
#include <string.h> //strerror()
/*open()*/
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[])
{
//打开指定的目录,打开失败返回NULL,成功则返回一个指向目录的指针
DIR *pDIR=opendir(argv[1]);
if(NULL==pDIR)//打开失败
{
perror("opendir");
return -1;
}
printf("opendir ok\n");
closedir(pDIR);
}
//打开成功:opendir ok
Paste_Image.png
- 打开文件目录进行遍历目录里面的内容
#include <stdio.h>
#include <string.h> //strerror()
/*open()*/
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[])
{
//打开指定的目录,打开失败返回NULL,成功则返回一个指向目录的指针
DIR *pDIR=opendir(argv[1]);
if(NULL==pDIR)//打开失败
{
perror("opendir:");
return -1;
}
printf("opendir ok\n");
struct dirent *pDirent=NULL;
pDirent=readdir(pDIR);//获得一个文件信息。遍历一个目录里的文件
while(NULL !=pDirent)//继续读(可能有好多目录)
{
printf("%s ",pDirent->d_name);
pDirent=readdir(pDIR);
}
printf("\n");
closedir(pDIR);
}
//./a.out 1
//./a.out ../上午
//./a.out ../../11.30
Paste_Image.png
- 遍历目录内容,判断是普通文件还是目录文件还是其他类型
#include <stdio.h>
#include <string.h>
/*stat()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*opendir()*/
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
//打开指定的目录,打开失败返回NULL,并设置错误号
//成功返回一个指向目录的指针
DIR *pDir = opendir(argv[1]);
if (NULL == pDir)
{
perror("opendir:");
return -1;
}
printf("opendir ok\n");
struct dirent *pDirent = NULL;
struct stat fileStat;
int ret = -1;
pDirent = readdir(pDir);
while (NULL != pDirent)
{
printf("%s ", pDirent->d_name);
ret = stat(pDirent->d_name, &fileStat);
if (0 == ret)
{
switch (fileStat.st_mode & S_IFMT)
{
case S_IFREG:
printf("这是一个普通的文件\n");
break;
case S_IFDIR:
printf("这是一个目录的文件\n");
break;
default:
printf("其他类型的文件\n");
break;
}
}
else if (-1 == ret)
{
perror("stat");
break;
}
pDirent = readdir(pDir);
}
printf("\n");
//返回到目录的头部
//rewinddir(pDirent);
//创建一个目录
//mkdir(pathname, mode);
//删除一个目录
//rmdir(pDrient);
closedir(pDir);
return 0;
}
//./a.out 1
//./a.out ../上午
Paste_Image.png
- 求一个文件的普通文件的个数,目录文件的个数,其他类型文件的个数
#include <stdio.h>
#include <string.h>
/*stat()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*opendir()*/
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[])
{
DIR *pDir=opendir(argv[1]);
if(NULL==pDir)
{
perror("opendir");
return -1;
}
printf("opendir ok\n");
struct dirent *pDirent=NULL;
struct stat fileStat;
int ret=-1;
pDirent=readdir(pDir);
int count=0,count1=0,count2=0;
while(NULL!=pDirent)
{
printf("%s ",pDirent->d_name);
ret=stat(pDirent->d_name,&fileStat);
if(0==ret)
{
switch(fileStat.st_mode & S_IFMT)
{
case S_IFREG:count++;break;
case S_IFDIR:count1++;break;
default:count2++;break;
}
}
else if(-1==ret)
{
perror("stat");
break;
}
pDirent=readdir(pDir);
}
printf("\n");
printf("普通文件的个数为:%d\n",count);
printf("目录文件的个数为:%d\n",count1);
printf("其他类型文件的个数为:%d\n",count2);
closedir(pDir);
}
//./a.out ../2
Paste_Image.png
进程
- 如何创建进程
- 如何使进程之间通信
- 如何销毁进程
进程与程序的区别
- 进程是动态的,程序是静态的
- 一个程序可以运行多个进程,但是一个进程只一个程序服务
进程控制块
如何查看一个正在运行的进程
- ps -A, kill -9 进程号
如何查看进程的运行状态
- top(表示CPU占了多少,占内存多少)
如何创建进程
- fork函数
- 子进程会完全拷贝父进程,包括代码,包括资源
- 父进程创建子进程,然后返回,子进程也返回,父进程返回子进程的pid,子进程返回0
- 父进程先返则先父进程
#include <unistd.h> //fork()
#include <stdio.h>
#include <string.h>
int main(void)
{
pid_t pid = -1;
int iNum = 0;
char caData[32] = {'\0'};
//子进程创建后,和父进程属于两个相互独立的进程
//父进程调用fork,这是一个系统调用,因此进入内核
//内核根据父进程复制出一个子进程,父子进程的PCB信息相同
//用户态代码和数据也完全相同。
//因此,子进程现在的状态看起来和父进程一样,做完了初始化
//刚调用了fork进入内核,还没有从内核返回。
//现在有两个一模一样的进程看起来都调用了fork进入内核等待
//从内核返回(实际上fork只调用了一次)。此外系统中还有其他
//进程等待从内核返回。是父进程先返回还是子进程先返回,还是
//父子进程都等待,其他进程先返回,这是不确定的。
//取决于内核的调度算法
pid = fork();
//fork成功:将子进程的id返回给父进程的pid变量
// 将0返回给子进程的pid变量
// 失败:返回-1给父进程的pid变量,子进程不会被创建
// 并且错误号会被设置
if (pid > 0) //父进程
{
printf("this is parent process\n");
strcpy(caData, "this is parent process\n");
iNum = 3;
}
else if (0 == pid) //子进程
{
printf("this is child process\n");
strcpy(caData, "this is child process\n");
iNum = 6;
}
else if (-1 == pid) //创建进程失败
{
perror("fork");
return -1;
}
int i = 0;
for (; i < iNum; i++)
{
printf("%s", caData);
sleep(1);
}
printf("Hello World\n");
return 0;
}
//父进程先结束,则是由祖宗进程对子进程进行善后
Paste_Image.png
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
pid_t pid=-1;
pid=fork();
if(pid>0)//父进程
{
printf("this is parent progress\n");
}
else if(pid==0)//子进程
{
printf("this is child progress\n");
}
else if(pid=-1)//创建进程失败
{
perror("fork");
return -1;
}
while(1)
{
}
printf("hello world\n");
return 0;
}
//后台运行:./a.out &
//同时创建两个进程:子进程与父进程
Paste_Image.png
Paste_Image.png
Paste_Image.png
- 父进程与子进程之间相互独立,父进程创建子进程,如果程序中不加while(1),则不能在后台显示,不加while(1)的结果如下:
进程如何杀死
- kill -9 +编号
僵尸进程
- 子进程结束后会释放一些资源,但是有些资源需要父进程进行释放,比如:进程号
- 解决办法:僵尸进程,已死的进程,但仍然在后台,kill不行,因为是已死的进程,只能杀死父进程,最后由init祖宗进程进行
- 此为僵尸进程只有杀死父进程,则才能消灭子进程,否则之间kill子进程则仍然会在后台显示,虽然已经杀死,但是父进程没有进行清理,则仍然会存留(形成僵尸进程实例)
#include <unistd.h>
#include <stdio.h>
#include <string.h>
//一个进程结束时会关闭所有的文件描述符,
//释放在用户空间分配的内存,
//但它的PCB还保留着,
//如果进程异常终止则保留着导致该进程终止的信号
//如果正常终止则保留退出状态:在终端可以用“$?”来查看
//父进程可以调用wait或waitpid获取这些信息,
//然后彻底清楚掉这个进程
//如果一个进程终止,但是其父进程尚未调用wait或者waitpid
//对他进行清理,这时的进程状态称之为僵尸进程。
//任何进程在刚终止的时候都是僵尸进程,
//正常情况下僵尸进程会立刻被父进程清理。
//僵尸进程的危害:
// 系统允许存在的进程数是有上限的。
// 若存在大量的僵尸进程,则可能创建新的进程由于没有
// 进程号分配而失败
//形成僵尸进程实例:
int main(void)
{
pid_t pid=-1;
pid=fork();
if(pid>0)//父进程
{
printf("this is parent progress\n");
while(1)
{}
}
else if(pid==0)//子进程
{
printf("this is child progress\n");
}
else if(pid=-1)//创建进程失败
{
perror("fork");
return -1;
}
while(1)
{}
}
Paste_Image.png
Paste_Image.png
- 先删除子进程(结果如下,<defunct>,仍然存留在后台中)
Paste_Image.png
- 删除父进程,结果如下:已清理好()
- 此为另一种解决方案(出力僵尸进程的方案)
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include<sys/wait.h>
#include<sys/types.h>
/*waitpid*/
//僵尸进程的处理方式
//1.将子进程的善后处理交给祖宗进程(父进程子在做自己的事,不方便对子进程清理)
// A-->B-->C:将B进程挂掉,那么C进程的清理工作由祖宗进程来清理
//2.父进程自己调用相应的函数来对子进程做善后处理
int main(void)
{
pid_t pid=-1;
pid=fork();
if(pid>0)//父进程
{
printf("this is parent progress\n");
//阻塞等待子进程的结束
//获得子进程的退出状态,并对子进程做清理工作
wait(NULL);
while(1)
{}
}
else if(pid==0)//子进程
{
printf("this is first child progress\n");
pid_t pid2=fork();
if(pid2>0)
{
return 0;
}
else if(0==pid2)
{
int i=0;
for(;i<3;i++)
{
printf("this is second child process\n");
}
return 0;
}
}
else if(pid=-1)//创建进程失败
{
perror("fork");
return -1;
}
}
- 创建一个父进程,写数据到文件里,子进程计算文件大小
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/*open()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd=-1;
pid_t pid=1;
pid=fork();
if(pid>0)
{
fd=open(argv[1],O_RDWR | O_CREAT | O_APPEND,S_IRUSR | S_IWUSR | S_IRGRP);
if(-1==fd)
{
printf("open error:%s\n",strerror(errno));
return -1;
}
char *pData="hello world ";
int ret=-1;
while(1)
{
ret=write(fd,pData,strlen(pData));
if(-1==ret)
{
perror("write");
return -1;
}
sleep(1);
}
}
else if(0==pid)
{
fd=open(argv[1],O_RDWR | O_CREAT | O_APPEND,S_IRUSR | S_IWUSR | S_IRGRP);
off_t offset=-1;
while(1)
{
offset=lseek(fd,0,SEEK_END);
if(-1==offset)
{
perror("lseek");
return -1;
}
printf("file size:%ld\n",offset);
sleep(1);
}
}
else if(-1==pid)
{
perror("fork");
return -1;
}
return 0;
}
//运行结果如下
Paste_Image.png
网友评论