文件I/O操做(1)

linux系統調用和用戶編程接口(api)html

系統調用是指在操做系統提供給用戶程序調用的一組「特殊」的接口,用戶程序能夠經過這組特殊的接口來獲取操做系統內核提供的服務,例如用戶能夠經過進程控制相關的系統調用來建立進程,實現進程調度,進程管理linux

爲何用戶不能直接訪問系統內核提供的服務?這是由於在linux中,爲了更好地保護內核空間,將程序運行的空間分爲內核空間和用戶空間(也就是常稱爲的內核態和用戶態)程序員

內核態和用戶態運行在不一樣的級別上,在邏輯上也是相互隔離的,新詞用戶進程在一般狀況下是不容許範圍內核數據,也沒法使用內核的函數,他們只能在用戶空間操做用戶數據,調用用戶空間的函數編程

可是,在有些狀況下,用戶空間的進程須要得到必定的系統服務,調用內核空間程序,這時操做系統就必須利用系統提供給用戶的特殊接口,系統調用規定用戶進程進入內核空間的具體位置,進行系統調用的時,程序從用戶空間進入內核空間,處理完後在返回用戶空間windows

linux系統調用部分是很是精簡的系統調用(只有250)他繼承了unix系統調用最基本和最有用的部分,這些系統調用按照功能和邏輯大體能夠分爲api

進程控制,進程間通訊,文件系統控制,系統控制,存儲管理,網絡管理,socket控制,用戶管理緩存

 

用戶編程的api網絡

前面講到的系統調用便不是直接與程序員進行交互,它僅僅是一個軟中斷機制向內核提出請求,以獲取內核服務的接口,在實際使用中,程序員調用的是用戶編程對應的接口--apisocket

linux中文件及文件描述符概述函數

在linux中對目錄和設備的操做都等同於對文件的操做,所以大大簡化了系統對不一樣設備的處理,linux中的文件主要分爲4種,普通文件,目錄文件,連接文件和設備文件,對於linux而言,全部對設備和文件的操做都是使用文件描述符來進行的

文件描述符是一個非負整數,他是一個索引值,並指向內核中每一個進程打開文件的記錄表,當打開一個現存文件,或者是建立一個新的文件時,內核就像進程返回一個文件描述符,但須要寫入文件時,也須要吧文件描述符做爲參數傳遞給相應的函數

 

一般一個進程啓動時,都會打開三個文件,標準輸入,標準輸出,標準出錯處理,對應文件描述符爲0,1,2。

基於文件描述符的I/0操做雖然不能移植到類linux之外的系統上去(如windows)但它每每是實現某些I/0操做的惟一途徑,基於文件描述符的I/O操做時linux中對經常使用的操做之一

 

底層文件I/O操做

這裏主要是5個函數open(),read(),write(),lseek(),和close()這些函數的特色是不帶緩存,直接對文件(包括設備)進行讀寫操做

open()函數用於打開或建立文件,在打開或建立文件時,能夠指定文件的屬性和用戶的權限等各類參數。

close()是一個用於關閉一個被打開的文件。當一個進程終止時,全部被他打開的文件都由內核自動關閉,不少程序都使用這一功能而不顯示的關閉一個文件

read()函數用於將從指定的文件描述符中讀取數據放到緩存區,並返回實際讀入的字節數,若返回0,則表示沒有數據可讀,即已經達到文件尾,讀操做文件從文件的當前指針位置開始,當從終端設備文件中讀取數據時,一般一次最多讀取一行

write()函數用於向打開的文件中寫入數據,寫操做從文件的當前指針位置開始,對磁盤文件進行寫操做,若磁盤已經寫滿,或者超出文件的長度,則write()函數返回失敗

lseek()函數用於在指定的文件描述符中將文件的指針定位到相應的位置,它只能用在可定位(可隨機訪問)文件操做中,管道,套接字,和大部分字符設備文件是不可定位的,因此在這些文件的操做中沒法使用lseek

open函數的原型 int open(const char *pathname ,int flags);pathname是指文件的路徑名和名稱,能夠是絕對路徑或者是相對路徑,flag 是指定了文件的打開方式

O_RDONLY 以只讀方式,要求文件存在

O_WRONLY以只寫的方式打開,要求文件存在

O_RDWR可讀可寫的方式打開,要求文件存在

O_CREAT 建立文件

O_EXCL建立互斥

O_APPEND 以追加的方式寫入首先要有寫權限

O_TRUNC 清空原文件內容

返回值 爲文件描述符,非負整數,文件後續操做的標誌

open的另一種原型爲int open(const char *pathname,int flags,mode_t mode)前面的參數和同樣,mode是指建立文件時的權限0x777 0x644 0x664等等

打開文件失敗的緣由分析:1文件不存在時指定可讀,2文件所在目錄無操做權限 3其餘緣由,文件操做權限,文件是否可用

close函數 函數原型爲int close (int fd);

fd爲open返回值的文件描述符,關閉文件後,該文件描述符將不可再用,返回值表示關閉是否成功,但咱們編程時不處理該返回值,打開文件必須關閉,不然會形成文件描述符的泄漏,特別是異常狀況,能夠關閉0,1,2;

示例代碼:

 

read 函數原型爲 int read(int fd, void *buf,int count);fd爲文件描述符(注意此處不能是文件名),buf爲存儲讀取的內容的內存地址(指針),必定不能是野指針或者是空指針,count是本次讀取的字節數,要求count要小於等於buf的大小,若是存儲字符串時,返回值爲成功讀取的字節數,若是讀取失敗,返回小於0的值,返回值爲0表示讀取到文件末尾

示例代碼:

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

int main(void)
{
              int fd1,size;
              char buf[128];

              fd1 = open("/etc/net/works",O_RDONLY);
              if(fd1<0)
                     {
                        printf("open fail\n");
                        exit(0);
                     }
              while(1)
                      {
                         size = read(fd1,buf,64);
                         if(size<0)
                                {
                                 printf("read error\n");
                                 exit(1);
                                 }
                         if(size ==0break;
                         buf[size+1] = '\0';
                         printf("%s",buf);

                       } 
              close(fd1);
       
              return 0;  
}                                                                                        

memset用於在某段內存中填充那一個數,函數包含的頭文件是#include<string.h>函數原型爲

void *memset(void *s,int c,size_t n);例如memset(buf,0,,128);

注意 :read函數會自動對文件的操做位置進行偏移,讀完幾個字節,以後就偏移幾個字節,自動偏移,若是到達文件末尾,不能再次偏移

若是讀取失敗的緣由:

1文件的讀取權限問題

2,文件沒有內容,須要注意,若是使用O_TRUNC時,文件內容已經被清楚

3:若是該處出現段錯誤,這主要考慮內存指針是否爲野指針或者是否越界

 

write函數;函數原型爲 int write(int fd, void *buf,int count);

fd爲寫入的文件描述符,buf爲須要寫入的內容的指針,count是寫入的字節數,這裏的buf要小於buf的有效值,返回值爲成功寫入的字節數,返回值小於0表示寫入失敗

write也會對文件的操做位置進行偏移,若是爲追加方式時,從文件的末尾開始寫入,若是寫入失敗,若是寫入失敗,這分析緣由爲:1)文件是否有寫權限,2)文件寫入多錯誤時,能夠查看內存是否越界,3)注意使用)O_TRUNC會清空原內容

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

int main(void)
{
        int fd1,fd2,size,f3;
        char buf[128];

        fd1 = open("/etc/xinetd.d/daytime",O_RDONLY);
        if(fd1<0)
        {
                printf("open fail\n");
                exit(1);
        }

        fd2 = open(""daytime1",O_RDWR|O_CREAT,777);
        if(fd2<0)
        {
                                                              1,1           Top
          printf("create daytime1 fail\n");
                exit(1);
        } 
        
        while(1)
        {
                memset(buf,0,127);
                size = read(fd1,buf,127);

                if(size<0)
                {
                        printf("read fail\n");
                        exit(1);
                }
                
                if(size==0)
                        break;

                buf[128]='\0';
                printf("%s",buf);


                f3 = write(fd2,buf,size);
                if(f3<0)
                {
                        printf("write fail\n");
                        exit(1);
                }

        }

        close(fd1);
        close(fd2);

        return 0;
}

 

 

 

 

 版權全部,轉載請註明轉載地址:http://www.cnblogs.com/fengdashen/p/3300614.html

相關文章
相關標籤/搜索