歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

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
plain copy
#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
plain copy
#include <unistd.h>
int close(int fd);
2、文件讀寫
read()函數從文件中讀取數據存放到緩沖區中,並返回實際讀取的字節數。若返回0,則表示沒有數據可讀,即已達到文件尾。讀操作從文件的當前讀寫位置開始讀取數據,當前讀寫位置自動往後移動。
函數原型:
[cpp] view
plain copy
#include <unistd.h>
ssize_t read(int fd, void *buf,size_t count);
函數傳入值:
fd 文件描述符;
buf 指定存儲器讀取數據的緩沖區;
count 指定讀出的字節數;
函數返回值:
成功:讀到的字節數;
0:已到達文件尾;
-1:出錯;
在讀到普通文件時,若讀到要求的字節數之前已到達問價你的尾部,則返回的字節數會小於指定讀出的字節數;
write()函數將數據寫入文件中,並返回實際寫入的字節數。寫操作從文件的當前讀寫位置開始寫入。對磁盤文件進行寫操作時,若磁盤已滿,write()函數返回失敗;
函數原型:
[cpp] view
plain copy
#include <unistd.h>
ssize_t write(int fd,void *buf ,size_t count);
函數傳入值:
fd 文件描述符
buf 指定存儲器寫入數據的緩沖區
count 指定讀出的字節數
函數返回值:
成功:已寫的字節數
-1:出錯

下面寫個簡單小程序,實現copy程序,完成文件的復制,代碼如下:
[cpp] view
plain copy
#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
plain copy
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
plain copy
#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
plain copy
#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
plain copy
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正確大小!
Copyright © Linux教程網 All Rights Reserved