Unix C (四)

文件:
    1、在Linux系統中,幾乎一切都是文件。目錄(使用vi目錄名驗證),內存(查看/proc/進程號/maps文件驗證),硬盤(查看/dev文件可驗證)以及其他的各種硬件設備都可以看成文件。比如:文件/dev/tty可以看成鍵盤和顯示器。
    2、在標準C中的文件操作:用FILE*代表fopen打開的一個文件;而在UC中用文件描述符(一個非負整數)代表打開一個文件。
    3、文件描述符自身不存儲任何文件信息,信息都存在文件表(本身比較龐大)中。文件描述符對應文件表。就像用UID代表進程一樣。
    4、在Linux來說,一個進程最多同時打開256個文件,描述符從3開始,0~2的描述符系統佔用,他們分別表示標準輸入,標準輸出和標準錯誤。
    5、文件函數:open(),close(),read(),write(),ioctl()。
        open()    打開一個文件,返回一個文件描述符
        read()    讀一個文件
        write()    寫一個文件
        close()    關閉一個文件
        ioctl()    控制文件的讀寫
    6、函數原型int open(const char *pathname, int flags);和int open(const char *pathname, int flags, mode_t mode);創建成功返回文件描述符,失敗返回-1。
            第一個參數:文件路徑包括文件名
            第二個參數:文件描述符權限標記
                flags取值:
                    O_RDONLY        只讀方式打開         \
                    O_WRONLY        只寫方式打開             --> 三種權限必選其一
                    O_RDWR        以可讀可寫方式打開    /
                    O_APPEND        從文件尾以追加方式打開。
                    創建標識:
                        O_CREAT        如果文件存在則打開,文件不存在就創建。
                        O_EXCL        如果文件文件不存在,創建文件;如果文件存在,返回-1,代表出錯。
                        O_TRUNC        清空文件內容後打開
                多個描述符一起使用要用按位或"|"連接。
            第三個參數:只有在創建文件時指定文件權限。該權限是指文件在硬盤上的操作權限(某些權限由於系統出於安全考慮會屏蔽某些權限)。
    7、函數原型:ssize_t read(int fd, void *buf, size_t count);也可以爲int read(int fd, void* buf, size_t size);
        參數:
            fd文件描述符,就是open的返回值
            buf是讀文件的首地址,任意類型都可
            size是buf的大小(有可能讀不滿)
        返回值:正數        真實讀到文件的字節數
              0        什麼都沒讀取
              -1        出現錯誤
    8、函數原型:ssize_t write(int fd, const void *buf, size_t count);也可以爲int write(int fd, void* buf, size_t lenght)
        參數:
            參數:
            fd文件描述符,就是open的返回值
            buf是寫文件的首地址,任意類型都可
            lenght是真實想要寫入的字節數
        返回值:正數        真實寫入文件的字節數
              0        什麼都沒寫

              -1        出現錯誤

實例:

(1)文件寫入比較:

C語言版:

#include <stdio.h>
#include <stdlib.h>

int main(){
    FILE * p_file = fopen("a.txt","wb");
    if(!p_file){
        perror("fopen"),exit(-1);
    }

    int i = 0;
    for(i = 0; i < 100000; i++){
        fwrite(&i,sizeof(int),1,p_file);
    }

    close(p_file);

    return 0;
}

UC普通版:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main(){
    int fd = open("b.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
    if(fd == -1){
        perror("open"),exit(-1);
    }

    int i = 0;
    for(i = 0; i < 100000; i++){
        write(fd,&i,4);
    }

    close(fd);

    return 0;
}

UC優化版:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
    char buf[100000] = {};   //自定義緩衝區
    
    int fd = open("c.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
    if(fd == -1){
        perror("open"),exit(-1);
    }

    int i = 0;
    for(i = 0; i < 100000; i++){
        buf[i%100000] = i;
        if(i%100000 == 99999){
            write(fd,buf,sizeof(buf));  //將緩衝區的內容寫入到文件
        }
    }

    close(fd);

    return 0;
}

執行時間對比:

原因:所有的標C函數都在用戶層定義了輸入/輸出緩衝區,作用就是累計到了一定數量以後再進入內核讀/寫一次。
            所有的UC函數都沒有定義緩衝區,但是可以由程序員自定義緩衝區提升效率,更加靈活。


(2)文件拷貝:

/*
   文件拷貝練習
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(void){
    //打開第一個文件,用於讀取裏面的內容
    int fdr  = open("1.png",O_RDONLY);
    if(-1 == fdr){     //檢測文件打開是否失敗
        perror("open1"),exit(-1);
    }

    //打開第二個文件,用於存儲複製第一個文件的內容
    int fdw = open("2.png",O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if(-1 == fdw){    //檢測文件打開是否失敗
        perror("open2"),exit(-1);
    }

    char buf[4096] = {};

    while(1){
        //讀取文件內容
        int res = read(fdr,buf,sizeof(buf));        //讀取第一個文件的內容
        if(-1 == res){       //判斷是否讀取有誤
            perror("read");
            break;
        }
        if(!res){            //判斷是否讀到了文件末尾
            break;
        }
        //寫入文件中
        write(fdw,buf,res);  //將第一個文件的內容寫到第二個文件中
    }
    
    //關閉文件
    close(fdr);
    close(fdw);

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章