生活随笔
收集整理的這篇文章主要介紹了
Linux 系统应用编程——文件I/O
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?Linux操作系統是基于文件概念的。文件是以字符序列構成的信息載體。根據這一點,可以把I/O設備當做文件來處理,因此,在磁盤上的普通文件進行交互所用的統一系統調用可以直接用于I/O設備。這樣大大簡化了系統對于不同設備的處理,提高了效率。Linux中的文件主要分為6種:普通文件、目錄文件、符號鏈接文件、管道文件、套接字文件和設備文件。
?????? 那么,內核如何區分和引用特定的文件呢?這里用到了一個重要的概念——文件描述符。對于Linux而言,所有的設備和文件的操作都是通過文件描述符來進行的。文件描述符是一個非負的整數,它是一個索引值,并指向在內核中每個進程打開文件的記錄表。當打開一個現存文件或創建一個新文件時,內核就向進程返回一個文件描述符;讀寫文件時,需要把文件描述符作為參數傳遞給相應的函數。
?????? 通常,一個進程啟動時,都會打開3個流:標準輸入、標準輸出和標準錯誤。這3個流分別對應文件描述符0、1? 和 2(對應的宏分別是STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO)。
????? 基于文件描述符的I/O操作雖然不鞥直接移植到類Linux以外的系統上去(如Windows),但它往往是實現某些I/O操作的唯一途徑,如Linux中底層文件操作函數、多路I/O、TCP/IP套接字編程接口等。同時,他們也很好地兼容POSIX標準,因此,可以很方便地移植到任何POSIX平臺上。基于文件描述符的I/O操作是Linux中最常用的操作之一。
????? 文件I/O相關函數:open() 、read() 、write() 、lseek() 和close() 。這些函數的特點是不帶緩沖,直接對文件(包括設備)進行讀寫操作。這些函數不是ANSI C的組成部分,而是POSIX相關標準來定義。
1、文件打開與和關閉
???????open()函數用于創建或打開文件,在打開或創建文件時可以指定文件打開方式及文件的訪問權限。
??????? 函數原型如下:
[cpp]?view plaincopy
#include?<sys/stat.h>?? #include?<fcntl.h>?? ?? int?open(const?char?*pathname,int?flags,int?perms);??
1)pathname: 被打開的文件名(可包括路徑名)
2)flags(文件打開方式,這里介紹幾個常用的)
O_RDONLY???只讀
O_WRONLY??只寫
O_RDWR?????? 可讀可寫
這三者必有其一
O_CREAT??? 如果文件不存在,就創建一個新文件,并用第三個參數為其設置權限;
O_TRUNC????若文件已經存在,那么會刪除文件中的全部原有數據,并且設置文件大小為0;
O_APPEND? 以添加方式打開文件,在寫文件時,文件讀寫文職自動指向文件的末尾,即將寫入的數據添加到文件的末尾;
3)perms 新建文件的存取權限
????? close()函數用于關閉一個被打開的文件。當一個進程終止時,所有打開的文件都有內核自動關閉。很多程序都利用這一特性而不顯示地關閉一個文件。
函數原型:
[cpp]?view plaincopy
#include?<unistd.h>?? ?? int?close(int?fd);??
?
2、文件讀寫
???????read()函數從文件中讀取數據存放到緩沖區中,并返回實際讀取的字節數。若返回0,則表示沒有數據可讀,即已達到文件尾。讀操作從文件的當前讀寫位置開始讀取數據,當前讀寫位置自動往后移動。
函數原型:
[cpp]?view plaincopy
#include?<unistd.h>?? ?? ssize_t?read(int?fd,?void?*buf,size_t?count);??
函數傳入值:
fd? 文件描述符;
buf 指定存儲器讀取數據的緩沖區;
count? 指定讀出的字節數;
函數返回值:
成功:讀到的字節數;
0:已到達文件尾;
-1:出錯;
在讀到普通文件時,若讀到要求的字節數之前已到達問價你的尾部,則返回的字節數會小于指定讀出的字節數;
????????write()函數將數據寫入文件中,并返回實際寫入的字節數。寫操作從文件的當前讀寫位置開始寫入。對磁盤文件進行寫操作時,若磁盤已滿,write()函數返回失敗;
函數原型:
[cpp]?view plaincopy
#include?<unistd.h>?? ?? ssize_t?write(int?fd,void??*buf?,size_t?count);??
函數傳入值:
fd? 文件描述符
buf? 指定存儲器寫入數據的緩沖區
count? 指定讀出的字節數
函數返回值:
成功:已寫的字節數
-1:出錯
下面寫個簡單小程序,實現copy程序,完成文件的復制,代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<unistd.h>?? #include?<sys/types.h>?? #include?<fcntl.h>?? #include?<sys/stat.h>?? #define?maxsize?256?? ?? int?main(int?argc,?char?*argv[])?? {?? ????int?fd1,fd2;?? ????int?byte;?? ????char?buffer[maxsize];?? ?? ????if(argc?!=?3)?? ????{?? ????????printf("command?error!\n");?? ????????return?-1;?? ????}?? ?? ????if((fd1?=?open(argv[1],O_RDONLY))?==?-1)?? ????{?? ????????perror("open?fails");?? ????????return?-1;?? ????}?? ?? ????if((fd2?=?open(argv[2],O_WRONLY?|?O_CREAT?|?O_TRUNC?,0664))?==?-1)?? ????{?? ????????perror("open?fails");?? ????????return?-1;?? ????}?? ?? ????while(1)?? ????{?? ????????if((byte?=?read(fd1,buffer,maxsize))?>?0)?? ????????????write(fd2,buffer,byte);?? ?? ????????if(byte?==?0)?? ????????????break;??? ????}?? ?? ????close(fd1);?? ????close(fd2);?? ?? ????return?0;?? }??
執行結果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/fileIO/open$?ls?-l?? total?16?? -rwxrwxr-x?1?fs?fs?7388?Jan??4?16:18?cp?? -rw-rw-r--?1?fs?fs??625?Jan??4?16:18?cp.c?? -rw-rw-r--?1?fs?fs??526?Jan??4?16:01?file1.c?? fs@ubuntu:~/qiang/fileIO/open$?./cp?file1.c?file2.c?? fs@ubuntu:~/qiang/fileIO/open$?ls?-l?? total?20?? -rwxrwxr-x?1?fs?fs?7388?Jan??4?16:18?cp?? -rw-rw-r--?1?fs?fs??625?Jan??4?16:18?cp.c?? -rw-rw-r--?1?fs?fs??526?Jan??4?16:01?file1.c?? -rw-rw-r--?1?fs?fs??526?Jan??4?16:19?file2.c?? fs@ubuntu:~/qiang/fileIO/open$???
我們可以看到,原來file2.c并不存在,執行完程序后,file2.c存在,且大小和file1.c相同;
?
3、文件定位
?????? lseek()函數對文件當前讀寫位置進行定位。它只能對可定位(可隨機訪問)文件操作。管道、套接字和大部分字符設備文件不支持此類操作;
函數原型:
[cpp]?view plaincopy
#include?<unistd.h>?? #include?<sys/types.h>?? ?? off_t?lseek(int?fd?,off_t?offset,int?whence);??
函數傳入值:
fd? 文件描述符
offset?? 相對于基準點whence 的偏移量。以字節為單位,正數表示向前移動,負數表示向后移動
whence 當前位置的基點
SEEK_SET:文件的起始位置
SEEK_CUR:文件當前讀寫位置
SEEK_END:文件的結束位置
函數的返回值:
成功:文件當前讀寫位置
-1:出錯
? ??? 我們可以通過lseek函數實現一個小功能:查看文件的大小,代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<unistd.h>?? #include?<fcntl.h>?? #include?<sys/stat.h>?? #include?<sys/types.h>?? ?? int?main(int?argc,?const?char?*argv[])?? {?? ????int?fd;?? ????int?length;?? ?? ????if(argc?!=?2)?? ????{?? ????????printf("command?error!\n");?? ????????return?-1;?? ????}?? ?? ????if((fd?=?open(argv[1],O_RDONLY))?==?-1)?? ????{?? ????????perror("open?fails");?? ????????return?-1;?? ????}?? ?? ????length?=?lseek(fd,0,SEEK_END);?? ?????? ????printf("The?length?of?%s?is?%d?bytes!\n",argv[1],length);?? ?? ????return?0;?? }??
執行結果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/fileIO/lseek$?ls?-l?? total?12?? -rwxrwxr-x?1?fs?fs?7308?Jan??4?16:47?lseek?? -rw-rw-r--?1?fs?fs??424?Jan??4?16:46?lseek.c?? fs@ubuntu:~/qiang/fileIO/lseek$?./lseek?lseek.c?? The?length?of?lseek.c?is?424?bytes!?? fs@ubuntu:~/qiang/fileIO/lseek$???
我們可以看到,得到了lseek.c正確大小!
總結
以上是生活随笔為你收集整理的Linux 系统应用编程——文件I/O的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。