程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> unix系統編程小結(一)------文件I/O

unix系統編程小結(一)------文件I/O

編輯:關於C語言

       基本看完了《unix/linux編程實踐教程》,實現了幾個小項目,覺得很不過瘾,書中對很多system call的細節和原理都沒講。在嘗試看linux內核分析的書時發現很多困難,所以拿起apue,繼續打基礎。讀著讀著,對apue上瘾了。這是題外話,就說這麼多。一.我對文件I/O的理解       文件I/O最基本的兩個函數就是read和write,書中也叫做unbuffered I/O。剛看到這個"unbuffered",我就奇怪,操作系統不是對所有的輸入輸出都會做緩存嗎(delayed write),為什麼還會存在unbuffered?但接著我就明白了,這裡的ubuffered,是指的是針對與read和write本身來說,他們是沒有緩存機制,比如read(fd,temp,100),在讀夠100個字節後或者遇到文件EOF後就返回,非常單純。而C庫函數中的fread和fwrite,就是利用緩存技術來調用read和write,可以說是buffered I/O。二.文件描述符       文件描述符是一個整型,可以理解為一個指向文件的指針(注:整型也可以理解為一個指針,並不是只有void*才可以被叫做指針)。需要注意的就是,一個進程在結束的時候會關閉所有打開的文件描述符,但是0,1,2除外。0,1,2,分別代表標准輸入流,標准輸出流和標准錯誤流。這3個文件描述符是由kernel打開和進行管理的,不需要我們來打開和關閉。三.文件共享機制       比較重要的就是file table的理解。file table包括了file status flags,the current file offset,a pointer to the v-node table entry for the file.比如對文件temp,調用一次open後,有fd1指向temp,也就有了一個file table。再對temp調用一次open後,有fd2指向temp,再生成一個file table(可以用dup,dup2實現,但又有不同,見下文)。這時,排除其他因素,我們的系統中有一個temp文件,2個文件描述符:fd1,fd2,兩個file table(表示同一個文件)。需要注意的是,如果對write操作加上了排他鎖,就無法用O_WRONLY同時打開兩個文件描述符了。但可以用O_RDONLY同時打開兩個文件描述符,fd1,fd2可以同時讀,而相應的,fd1指向的file table的current file offset自然可以不同於fd2指向的,這也就可以很容易地理解多個file table的作用了。四.system call原理與分析       我喜歡用函數來總結所學的東西,感覺比較實在。       1.lseek(fd,5,SEEK_SET).修改current offset.返回新的offset.       2.open(file,O_RDWR).不贅述細節,詳見man。先寫一個問題,就是O_SYNC,我無法利用代碼來感受這個option,如果您能幫忙,小弟我非常感激。值得注意的就是O_APPEND,這個很強大的東西,跟>>重定向的"添加到末尾"是一樣的。特別注意,當open(file,O_RDWR | O_APPEND)後,write與read得到的待遇並不相同。每個被打開的文件都有一個current offset,可以用lseek對這個offset進行修改。先貼出代碼:復制代碼

int main()
{
    int fd;
    char buf[100]="abcde";
    //注:temp中只有一行aaaaabbbbbccccc.
    if( (fd=open("temp",O_RDWR|O_APPEND))<0 )
        err_sys("error open!");
    if(lseek(fd,5,SEEK_SET)==-1)
        err_sys("error lseek!");
    if( read(fd,buf,5)<0 ) 
        err_sys("error read!");
    buf[5]='\0';
    printf("%s\n",buf);
    //if(write(fd,buf,5)!=5)
    //    err_sys("write error");
    return 0;
}
復制代碼         當利用lseek修改current offset為5時,再read,結果如下:?bbbbb           這說明read可以不受O_APPEND的影響,可以自由讀取文件中任意位置的內容。將上述代碼這樣修改後:復制代碼
int main()
{
    int fd;
    char buf[100]="abcde";
    //注:temp中只有一行aaaaabbbbbccccc.
    if( (fd=open("temp",O_RDWR|O_APPEND))<0 )
        err_sys("error open!");
    //if(lseek(fd,5,SEEK_SET)==-1)
    //    err_sys("error lseek!");
    //if( read(fd,buf,5)<0 ) 
    //    err_sys("error read!");
    //buf[5]='\0';
    //printf("%s\n",buf);
    if(write(fd,buf,5)!=5)
        err_sys("write error");
    return 0;
}
復制代碼         temp文件結果如下:?aaaaabbbbbcccccabcde  啊,lseek被O_APPEND屏蔽了?哈哈,不是被屏蔽了。原理是這樣的,在每次write之前,系統都因為O_APPEND而將current offset設置為文件的末尾,這就說明了上述結果。       3.fcntl(fd,F_GETFL,0).修改文件屬性。       4.dup(fd1).   dup2(fd1,fd2).都返回復制後的文件描述符。與兩次open得到兩個文件描述符不同的是,dup2(fd1,fd2)得到的fd2與fd1共享一個file table,而前者是分別擁有一個file table。自然,用read,write在處理fd1,fd2時,就會對兩者都起作用了。dup,dup2都是原子操作,而
close(fd2);
fcntl(fd1,F_DUPFD,fd2);
        可以實現dup2的功能,但會破壞其原子性。五.總結        基礎,原理,這都是需要掌握的。之前我有些激進了,想盡快去讀linux內核,現在看來,還有很長的路要走。六.我的一些筆記(有些摘自apue)        1.off_t 是一個long int        2.read,write這兩個system call在使用時會改變當前的offset        3.read,write starts at the file's current offset.        4. size_t 是為了方便系統之間的移植而定義的,是unsigned int.    ssize_t是signed size_t        5.the lseek fnction modifies only the current file offset in the file table entry . No I/O takes place.        6.Any operation that requires more that one function call cannot be atomic,as there is always the possibility that the kernel can temporarily suspend the process between the two function calls.        7.creat(filename,FILE_MODE).如果filename文件已經存在,將會刪除filename的所有內容   8.delayed write:When we write data to a file ,the data is normally copied by the kernel into one of its buffers and queued for writing to disk at some later time.   9.cat不直接接受標准輸入。 比如 more file1 | cat file2 的結果只會輸出file2,而這樣more file1 | cat - file2就會輸出file1和file2了。注:-可以用/dev/fd/0替代,表示連結標准輸入.   10.用read,write系統調用時,用戶沒有對輸入輸出做緩存,但是內核是會對所有輸入輸出做緩存的。可以這樣說,在這個進程的user time沒有進行緩存,但是system time在進行緩存   11.O_SYNC會一直起作用.而fsync和fdatasync是一次性的操作。   12.每次open系統調用後,都會生成一個新的file table entry.        13.注意write,read,printf等函數的'\0'問題   14.2>&1 是將2重定向到1,也就是將stderr重定向到stdout,就是讓stderr也指向stdout。再抽象一些,2>&1,就是將文件描述符2重定向到文件描述符1所指向的文件,使得二者指向同一個文件。   參考資料:apue(unix環境高級編程)        如果您覺得我的文章對您有幫助,請您贊一下,非常感謝!

本文出自 “Neil的博客” 博客,請務必保留此出處http://neilhappy.blog.51cto.com/5504414/1078667

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved