系统编程-文件操作3

2016-12-01  本文已影响0人  帅碧
  • 作业:在文件任意位置处插入数据

#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(测试)

  1. 测试文件是否存在
#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

  1. 测试文件是否有可读可写权限
#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

  1. 测试文件是否有可执行权限
#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

进程

  1. 如何创建进程
  2. 如何使进程之间通信
  3. 如何销毁进程

进程与程序的区别

  • 进程是动态的,程序是静态的
  • 一个程序可以运行多个进程,但是一个进程只一个程序服务

进程控制块

如何查看一个正在运行的进程

  • 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
  • 父进程与子进程之间相互独立,父进程创建子进程,如果程序中不加while(1),则不能在后台显示,不加while(1)的结果如下:
Paste_Image.png

进程如何杀死

  • kill -9 +编号

僵尸进程

  • 子进程结束后会释放一些资源,但是有些资源需要父进程进行释放,比如:进程号
  • 解决办法:僵尸进程,已死的进程,但仍然在后台,kill不行,因为是已死的进程,只能杀死父进程,最后由init祖宗进程进行
  1. 此为僵尸进程只有杀死父进程,则才能消灭子进程,否则之间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
  • 先删除子进程(结果如下,<defunct>,仍然存留在后台中)
Paste_Image.png
  • 删除父进程,结果如下:已清理好()
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
上一篇下一篇

猜你喜欢

热点阅读