文件操作

文件

1.文件

Linux系統可以看成是一個由文件組成的系統,在linux系統中,基本上所有的設備,硬件,資源都被看成一個文件,比如鍵盤、鼠標(/dev/input/mouse0)
文件按存儲又可以分爲ASC(阿斯卡嗎)文件和二進制文件,阿斯卡嗎文件雖然佔的內存空間比較的多,但是可以對字符進行逐個的處理。

2.文件描述符

在linux下一切皆文件,文件描述符是內核爲了高效的管理已經被打開的文件所創建的索引,它是一個非負整數,用於指代被打開的文件,所有執行I/O操作的系統調用都是通過文件描述符完成的。
在linux中,進程是通過文件描述符fd(file descriptors 簡稱fd)來訪問文件的,文件描述符實際上是一個整數。在程序剛啓動的時候,默認有三個文件描述符,分別是:0(代表標準輸入),1(代表標準輸出),2(代表標準錯誤)。再打開一個新的文件的話,它的文件描述符就是3。
POSIX標準規定,每次打開的文件時(含socket)必須使用當前進程中最小可用的文件描述符號碼。

3.API

os操作系統提供給應用程序的接口就叫做API,而標準庫的文件操作函數實質也是調用的API,在linux下man 2 可以查看這些文件操作的函數。
同時,下面幾個系統調用的函數在我們的標準C裏基本上都有對應的函數實現,比如fope對應open, fclose對應close, fread對應read, fwrite對應wirte。也可以實現對文件的操作。

文件的基本操作

(1)文件的打開(open)
功能:打開文件
返回值:若成功爲文件描述符fd,若出錯爲- 1 (與fopen區別開,fopen返回的是指針,出錯返回NULL,因爲他返回的是FILE指針)
pathname是要打開或創建的文件的名字。
flags參數可用來說明此函數的多個選擇項。
對於open函數而言,僅當創建新文件時才使用第三個參數。
這裏寫圖片描述

用下列一個或多個常數進行或運算構成oflag參數(這些常數定義在<fcntl.h>頭文件中):
上面三個頭文件是用open這個系統調用時用到的從這兒也能區分出標準C和系統調用的區別,頭文件不一樣。
flags參數 說明
O_RDONLY 只讀打開。(互斥)
O_WRONLY 只寫打開。(互斥)
O_RDWR 讀、寫打開。(互斥)
O_APPEND 每次寫時都加到文件的尾端。
O_CREAT 若此文件不存在則創建它。使用此選擇項時,需同時說明第三個參數mode,用其說明該新文件的存取許可權位。
O_EXCL 如果同時指定了O_CREAT,而文件已經存在,則出錯。此參數用於測試文件是否存在,如果不存在,則創建此文件成爲一個原子操作。
O_TRUNC 如果此文件存在,則將其長度截短爲0。
O_NOCTTY 如果pathname指的是終端設備,則不將此設備分配作爲此進程的控制終端。
O_NONBLOCK 如果pathname指的是一個FIFO、一個塊特殊文件或一個字符特殊文件,則此選擇項爲此文件的本次打開操作和後續的I/O操作設置非阻塞方式。
O_SYNC 使每次write都等到物理I/O操作完成。

(2)文件的關閉(close)
功能:關閉一個打開文件
返回:若成功爲0,若出錯爲- 1
當一個進程終止時,它所有的打開文件都由內核自動關閉。很多程序都使用這一功能而不顯式地用close關閉打開的文件。
上面幾個系統調用的函數在我們的標準C裏基本上都有對應的函數實現,比如fope對應open, fclose對應close, fread對應read, fwrite對應wirte。
這裏寫圖片描述

(3)文件的寫(write)
功能;向打開文件寫數據。
返回:若成功爲已寫的字節數,若出錯爲- 1。
其返回值通常與參數count的值不同,否則表示出錯。write出錯的一個常見原因是:磁盤已寫滿,或者超過了對一個給定進程的文件長度限制。
對於普通文件,寫操作從文件的當前位移量處開始。如果在打開該文件時,指定了O_APPEND選擇項,則在每次寫操作之前,將文件位移量設置在文件的當前結尾處。在一次成功寫之後,該文件位移量增加實際寫的字節數。
這裏寫圖片描述

(4)文件的讀(read)
功能: 從打開文件中讀數據
返回:讀到的字節數,讀不到字節返回0,若count 爲0返回0,若出錯爲- 1。
有多種情況可使實際讀到的字節數少於要求讀字節數:
— 讀普通文件時,在讀到要求字節數之前已到達了文件尾端。例如,若在到達文件尾端之前還有3 0個字節,而要求讀1 0 0個字節,則read返回3 0,下一次再調用read時,它將返回0 (文件尾端)。
— 當從終端設備讀時,通常以行爲單位,讀到換行符就返回。
— 當從網絡讀時,網絡中的緩衝機構可能造成返回值小於所要求讀的字節數。
— 讀操作從文件的當前位移量處開始,在成功返回之前,該位移量增加實際讀得的字節數。
這裏寫圖片描述

(4)lseek函數
每個打開文件都有一個與其相關聯的“當前文件偏移量”。它是一個非負整數,用以度量從文件開始處計算的字節數。通常,讀、寫操作都從當前文件偏移量處開始,並使偏移量增加所讀或寫的字節數。按系統默認,當打開一個文件時,除非指定O_APPEND選擇項,否則該位移量被設置爲0。
功能:設置文件內容讀寫位置
返回:若成功爲新的文件位移,若出錯爲- 1。
對參數offset 的解釋與參數whence的值有關。
這裏寫圖片描述
若whence是SEEK_SET,則將該文件的文件位移指針設置爲距文件開始處offset 個字節。如果offset是0,就是回到文件首,返回值是0
若whence是SEEK_CUR ,則將該文件的位移量設置爲其當前值加offset,offset可爲正或負。如果offset是0,就是返回當前文件位移指針位置。
若whence是SEEK_END ,則將該文件的文件位移指針設置爲文件長度加offset,offset可爲正或負。如果offset是0,就是返回當前文件位移尾指針位置。
注意:
可以調用lseek顯式地定位一個打開文件。
lseek僅記錄當前文件的偏移量,而不會對文件進行I/O操作。
lseek的偏移量可以超過當前文件的字節總數,從而在文件中產生一個hole

操作實例

(1)用open打開文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define PATH "test.txt"

int main(void)
{
    int fd = -1;
    int cnt = 5;
    fd = open(PATH,O_CREAT|O_RDWR);
    if(-1 == fd)
    {
        perror("This file open failed!");
        return -1;
    }
    else
    {
        printf("This file open successed!");
    }
}

這裏寫圖片描述

(2)用write/read讀寫文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define PATH "test.txt"

int main(void)
{
    int fd = -1;
    int cnt = 5;
    fd = open(PATH,O_CREAT|O_RDWR);
    if(-1 == fd)
    {
        perror("This file open failed!\n");
        return -1;
    }
    else
    {
        printf("This file open successed!\n");
    }
    char buf[20]={0};//注意,在這裏一定要給buf初始化,若未曾初始化,則read出意想不到的結果,比如:buf =p@或者buf =�@
    int n_write = 0;
    while(cnt--){
        n_write = write(fd, "AC", 2);
        printf("給fd寫入了%d個字符\n", n_write);
        //sleep(1);
    }
    lseek(fd,0, SEEK_SET);//在這裏爲什麼要用lseek?因爲我們剛開始打開文件,然後寫文件,寫到了文件尾,這個時候如果不用lseek,直接讀取的話,讀出來的東西是我們寫完的東西后邊的東西,也就是說沒有東西,lseek則能幫我們把位置重新回到文件頭來讀取我們寫入的東西
    read(fd,buf,20);
    printf("buf =%s\n",buf);
    close(fd);
    return 0;
}

這裏寫圖片描述
(2)用fopen打開文件:
請注意,在這裏fopen與open的區別

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define PATH "test/txt"

int main(void){
    FILE* fp;
    fp = fopen("test.txt","r+");
    if(NULL == fp)
    {
        perror("failed!\n");
    }
    else
    {
        printf("successen!\n");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章