系統(tǒng)編程-文件操作3

  • 作業(yè):在文件任意位置處插入數(shù)據(jù)

#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里面的內(nèi)容復(fù)制到caFile

    int ret=-1;
    strcat(caFile,".old");
    ret=rename(argv[1],caFile);//將原來的文件重命名
    if(-1==ret)
    {
        printf("rename error:%s\n",strerror(errno));//如果錯(cuò)誤,打印錯(cuò)誤信息
        return -1;
    }
    int fdNew=-1;
    fdNew=open(argv[1],O_WRONLY | O_CREAT,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);//寫打開,訪問權(quán)限
    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)//將指定位置前面的數(shù)據(jù)讀出來
    {
        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;
            
        }
    }
    //在制定的位置插入該數(shù)據(jù)
    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
//結(jié)果為:在第第四個(gè)位置插入數(shù)據(jù):
//1234$$$qqrhtewrywywruiepitrew$$$567890abcdefghijklmn

ACCESS(測試)

  1. 測試文件是否存在
#include<unistd.h>
#include<stdio.h>//perror
//mode:
//    F_OK:測試文件是否存在
//    R_OK:測試用戶是否對文件具有可讀權(quán)限
//    W_OK:測試用戶是否對文件具有可寫權(quán)限
//    X_OK:測試用戶是否對文件具有可執(zhí)行權(quán)限
//測試用戶對于指定的文件是否具有mode權(quán)限
//如果有,則函數(shù)返回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");//如果錯(cuò)誤,則會(huì)打印access:錯(cuò)誤信息
        return -1;
    }
    else if(0==ret)
    {
        printf("file exist\n");
    }
    return 0;
}
//./a.out test.data

  1. 測試文件是否有可讀可寫權(quán)限
#include<unistd.h>
#include<stdio.h>//perror
int main(int argc,char *argv[])
{
    int ret=-1;
    ret=access(argv[1],R_OK | W_OK);//測試文件是否有可讀可寫的權(quán)限
    if(-1==ret)
    {
        perror("access");//如果錯(cuò)誤,則會(huì)打印access:錯(cuò)誤信息
        return -1;
    }
    else if(0==ret)
    {
        printf("user has those permissions\n");
    }
    return 0;
}
//./a.out test.data

  1. 測試文件是否有可執(zhí)行權(quán)限
#include<unistd.h>
#include<stdio.h>//perror   
int main(int argc,char *argv[])
{
    int ret=-1;
    ret=access(argv[1],X_OK);//測試文件是否有可讀可寫的權(quán)限
    if(-1==ret)
    {
        perror("access");//如果錯(cuò)誤,則會(huì)打印access:錯(cuò)誤信息
        return -1;
    }
    else if(0==ret)
    {
        printf("user has those permissions\n");
    }
    return 0;
}

OPENDIR(打開目錄)

  • 打開一個(gè)文件目錄
#include <stdio.h>
#include <string.h>  //strerror()
/*open()*/
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[])
{
    //打開指定的目錄,打開失敗返回NULL,成功則返回一個(gè)指向目錄的指針
    DIR *pDIR=opendir(argv[1]);
    if(NULL==pDIR)//打開失敗
    {
        perror("opendir");
        return -1;
    }
    printf("opendir ok\n");
    closedir(pDIR);
}

//打開成功:opendir ok

Paste_Image.png
  • 打開文件目錄進(jìn)行遍歷目錄里面的內(nèi)容
#include <stdio.h>
#include <string.h>  //strerror()
/*open()*/
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[])
{
    //打開指定的目錄,打開失敗返回NULL,成功則返回一個(gè)指向目錄的指針
    DIR *pDIR=opendir(argv[1]);
    if(NULL==pDIR)//打開失敗
    {
        perror("opendir:");
        return -1;
    }
    printf("opendir ok\n");
    struct dirent *pDirent=NULL;
    pDirent=readdir(pDIR);//獲得一個(gè)文件信息。遍歷一個(gè)目錄里的文件
    while(NULL !=pDirent)//繼續(xù)讀(可能有好多目錄)
    {
        printf("%s ",pDirent->d_name);
        pDirent=readdir(pDIR);
    }
    printf("\n");
    closedir(pDIR);
}
//./a.out 1
//./a.out ../上午
//./a.out ../../11.30

Paste_Image.png
  • 遍歷目錄內(nèi)容,判斷是普通文件還是目錄文件還是其他類型
#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,并設(shè)置錯(cuò)誤號(hào)
    //成功返回一個(gè)指向目錄的指針
    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("這是一個(gè)普通的文件\n");
                break;
            case S_IFDIR:
                printf("這是一個(gè)目錄的文件\n");
                break;
            default:
                printf("其他類型的文件\n");
                break;
            }
        }
        else if (-1 == ret)
        {
            perror("stat");
            break;
        }
        pDirent = readdir(pDir);
    }
    printf("\n");

    //返回到目錄的頭部
    //rewinddir(pDirent);
    //創(chuàng)建一個(gè)目錄
    //mkdir(pathname, mode);
    //刪除一個(gè)目錄
    //rmdir(pDrient);

    closedir(pDir);

    return 0;
}
//./a.out 1
//./a.out ../上午

Paste_Image.png
  • 求一個(gè)文件的普通文件的個(gè)數(shù),目錄文件的個(gè)數(shù),其他類型文件的個(gè)數(shù)
#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("普通文件的個(gè)數(shù)為:%d\n",count);
    printf("目錄文件的個(gè)數(shù)為:%d\n",count1);
    printf("其他類型文件的個(gè)數(shù)為:%d\n",count2);
    closedir(pDir);
}
//./a.out ../2


Paste_Image.png

進(jìn)程

  1. 如何創(chuàng)建進(jìn)程
  2. 如何使進(jìn)程之間通信
  3. 如何銷毀進(jìn)程

進(jìn)程與程序的區(qū)別

  • 進(jìn)程是動(dòng)態(tài)的,程序是靜態(tài)的
  • 一個(gè)程序可以運(yùn)行多個(gè)進(jìn)程,但是一個(gè)進(jìn)程只一個(gè)程序服務(wù)

進(jìn)程控制塊

如何查看一個(gè)正在運(yùn)行的進(jìn)程

  • ps -A, kill -9 進(jìn)程號(hào)

如何查看進(jìn)程的運(yùn)行狀態(tài)

  • top(表示CPU占了多少,占內(nèi)存多少)

如何創(chuàng)建進(jìn)程

  • fork函數(shù)
  • 子進(jìn)程會(huì)完全拷貝父進(jìn)程,包括代碼,包括資源
  • 父進(jìn)程創(chuàng)建子進(jìn)程,然后返回,子進(jìn)程也返回,父進(jìn)程返回子進(jìn)程的pid,子進(jìn)程返回0
  • 父進(jìn)程先返則先父進(jìn)程

#include <unistd.h>   //fork()
#include <stdio.h>
#include <string.h>

int main(void)
{
    pid_t pid = -1;
    int iNum = 0;
    char caData[32] = {'\0'};
    //子進(jìn)程創(chuàng)建后,和父進(jìn)程屬于兩個(gè)相互獨(dú)立的進(jìn)程
    //父進(jìn)程調(diào)用fork,這是一個(gè)系統(tǒng)調(diào)用,因此進(jìn)入內(nèi)核
    //內(nèi)核根據(jù)父進(jìn)程復(fù)制出一個(gè)子進(jìn)程,父子進(jìn)程的PCB信息相同
    //用戶態(tài)代碼和數(shù)據(jù)也完全相同。
    //因此,子進(jìn)程現(xiàn)在的狀態(tài)看起來和父進(jìn)程一樣,做完了初始化
    //剛調(diào)用了fork進(jìn)入內(nèi)核,還沒有從內(nèi)核返回。
    //現(xiàn)在有兩個(gè)一模一樣的進(jìn)程看起來都調(diào)用了fork進(jìn)入內(nèi)核等待
    //從內(nèi)核返回(實(shí)際上fork只調(diào)用了一次)。此外系統(tǒng)中還有其他
    //進(jìn)程等待從內(nèi)核返回。是父進(jìn)程先返回還是子進(jìn)程先返回,還是
    //父子進(jìn)程都等待,其他進(jìn)程先返回,這是不確定的。
    //取決于內(nèi)核的調(diào)度算法
    pid = fork();
    //fork成功:將子進(jìn)程的id返回給父進(jìn)程的pid變量
    //          將0返回給子進(jìn)程的pid變量
    //    失敗:返回-1給父進(jìn)程的pid變量,子進(jìn)程不會(huì)被創(chuàng)建   
    //          并且錯(cuò)誤號(hào)會(huì)被設(shè)置
    if (pid > 0)  //父進(jìn)程
    {
        printf("this is parent process\n");
        strcpy(caData, "this is parent process\n");
        iNum = 3;
    }
    else if (0 == pid)  //子進(jìn)程
    {
        printf("this is child process\n");
        strcpy(caData, "this is child process\n");
        iNum = 6;
    }
    else if (-1 == pid)  //創(chuàng)建進(jìn)程失敗
    {
        perror("fork");
        return -1;
    }
    int i = 0;
    for (; i < iNum; i++)
    {
        printf("%s", caData);
        sleep(1);   
    }

    printf("Hello World\n");
    return 0;
}


//父進(jìn)程先結(jié)束,則是由祖宗進(jìn)程對子進(jìn)程進(jìn)行善后

Paste_Image.png
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父進(jìn)程
    {
        printf("this is parent progress\n");    
    }
    else if(pid==0)//子進(jìn)程
    {
        printf("this is child progress\n"); 
    }
    else if(pid=-1)//創(chuàng)建進(jìn)程失敗
    {
        perror("fork");
        return -1;
    }
    while(1)
    {
    }
    printf("hello world\n");
    return 0;
}
//后臺(tái)運(yùn)行:./a.out &
//同時(shí)創(chuàng)建兩個(gè)進(jìn)程:子進(jìn)程與父進(jìn)程

Paste_Image.png
Paste_Image.png
  • 父進(jìn)程與子進(jìn)程之間相互獨(dú)立,父進(jìn)程創(chuàng)建子進(jìn)程,如果程序中不加while(1),則不能在后臺(tái)顯示,不加while(1)的結(jié)果如下:
Paste_Image.png

進(jìn)程如何殺死

  • kill -9 +編號(hào)

僵尸進(jìn)程

  • 子進(jìn)程結(jié)束后會(huì)釋放一些資源,但是有些資源需要父進(jìn)程進(jìn)行釋放,比如:進(jìn)程號(hào)
  • 解決辦法:僵尸進(jìn)程,已死的進(jìn)程,但仍然在后臺(tái),kill不行,因?yàn)槭且阉赖倪M(jìn)程,只能殺死父進(jìn)程,最后由init祖宗進(jìn)程進(jìn)行
  1. 此為僵尸進(jìn)程只有殺死父進(jìn)程,則才能消滅子進(jìn)程,否則之間kill子進(jìn)程則仍然會(huì)在后臺(tái)顯示,雖然已經(jīng)殺死,但是父進(jìn)程沒有進(jìn)行清理,則仍然會(huì)存留(形成僵尸進(jìn)程實(shí)例)
#include <unistd.h>
#include <stdio.h>
#include <string.h>

//一個(gè)進(jìn)程結(jié)束時(shí)會(huì)關(guān)閉所有的文件描述符,
//釋放在用戶空間分配的內(nèi)存,
//但它的PCB還保留著,
//如果進(jìn)程異常終止則保留著導(dǎo)致該進(jìn)程終止的信號(hào)
//如果正常終止則保留退出狀態(tài):在終端可以用“$?”來查看
//父進(jìn)程可以調(diào)用wait或waitpid獲取這些信息,
//然后徹底清楚掉這個(gè)進(jìn)程

//如果一個(gè)進(jìn)程終止,但是其父進(jìn)程尚未調(diào)用wait或者waitpid
//對他進(jìn)行清理,這時(shí)的進(jìn)程狀態(tài)稱之為僵尸進(jìn)程。

//任何進(jìn)程在剛終止的時(shí)候都是僵尸進(jìn)程,
//正常情況下僵尸進(jìn)程會(huì)立刻被父進(jìn)程清理。

//僵尸進(jìn)程的危害:
//    系統(tǒng)允許存在的進(jìn)程數(shù)是有上限的。
//    若存在大量的僵尸進(jìn)程,則可能創(chuàng)建新的進(jìn)程由于沒有
//    進(jìn)程號(hào)分配而失敗


//形成僵尸進(jìn)程實(shí)例:
int main(void)
{
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父進(jìn)程
    {
        printf("this is parent progress\n");
        while(1)
        {}
    }
    else if(pid==0)//子進(jìn)程
    {
        printf("this is child progress\n");
    
    }
    else if(pid=-1)//創(chuàng)建進(jìn)程失敗
    {
        perror("fork");
        return -1;
    }
    while(1)
    {}
}


Paste_Image.png
  • 先刪除子進(jìn)程(結(jié)果如下,<defunct>,仍然存留在后臺(tái)中)
Paste_Image.png
  • 刪除父進(jìn)程,結(jié)果如下:已清理好()
Paste_Image.png
  • 此為另一種解決方案(出力僵尸進(jìn)程的方案)

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include<sys/wait.h>
#include<sys/types.h>
/*waitpid*/
//僵尸進(jìn)程的處理方式
//1.將子進(jìn)程的善后處理交給祖宗進(jìn)程(父進(jìn)程子在做自己的事,不方便對子進(jìn)程清理)
//  A-->B-->C:將B進(jìn)程掛掉,那么C進(jìn)程的清理工作由祖宗進(jìn)程來清理
//2.父進(jìn)程自己調(diào)用相應(yīng)的函數(shù)來對子進(jìn)程做善后處理
int main(void)
{
    pid_t pid=-1;
    pid=fork();
    if(pid>0)//父進(jìn)程
    {
        printf("this is parent progress\n");
        //阻塞等待子進(jìn)程的結(jié)束
        //獲得子進(jìn)程的退出狀態(tài),并對子進(jìn)程做清理工作
        wait(NULL);
        while(1)
        {}
    }
    else if(pid==0)//子進(jìn)程
    {
        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)//創(chuàng)建進(jìn)程失敗
    {
        perror("fork");
        return -1;
    }
}

  • 創(chuàng)建一個(gè)父進(jìn)程,寫數(shù)據(jù)到文件里,子進(jìn)程計(jì)算文件大小

#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;
}

//運(yùn)行結(jié)果如下

Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢閱讀 99,529評論 9 467
  • 1、第八章 Samba服務(wù)器2、第八章 NFS服務(wù)器3、第十章 Linux下DNS服務(wù)器配站點(diǎn),域名解析概念命令:...
    哈熝少主閱讀 3,771評論 0 10
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,218評論 2 33
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,881評論 18 139
  • 以前看書,我喜歡看方法論方面的書。現(xiàn)在則看閑書居多。不過分講求書本帶來的實(shí)用性和功用性了。也算是隨心隨性吧。為什么...
    左佳妮閱讀 777評論 2 2