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

Linux系統文件I/O編程(一) open()等基本函數

Linux文件I/O系統概述

虛擬文件系統(VFS)

Linux系統成功的關鍵因素之一就是具有與其 他操作系統和諧共存的能力。Linux系統的文件系統由兩層結構構建:第一層是虛擬文件系統(VFS),第二層 是各種不同的具體的文件系統。

VFS就是把各種具體的文件系統的公共部分抽取出來,形成一個抽象層 ,是系統內核的一部分,它位於用戶程序和具體的文件系統之間。它對用戶提供了標准的文件系統調用接口, 對具體的文件系統(如EXT2、FAT32等),它通過一系列的對不同文件系統公用的函數指針來實際調用具體的 文件系統函數,完成實際的各有差異的操作。任何使用文件系統的程序必須經過這層接口來使用它。通過這樣 的方式,VFS就對用戶屏蔽了底層文件系統的實現細節和差異。

VFS的作用:①對具體的文件系統的數 據結構進行抽象,以一種統一的數據結構進行管理;②接受用戶層的系統調用,如open()、read()、write() 、stat()、link()等;③支持多種具體文件系統之間的相互訪問,接受內核其他子系統的操作請求,例如,內 存管理和進程調度。

VFS在linux系統中的位置如下圖1所示:

通過命令:cat /proc/filesystems 可以查看系統中支持哪些文件系統

第一列說明文件 系統是否需要掛接在一個塊設備上。nodev表明後面的文件系統不需要掛接在塊設備上。

第二列是內核 支持的文件系統。

Linu中的文件及文件描述符

與windows不同,Linux操作系統都是基於文件概 念的(這個很很重要啊),文件是以字符序列構成的信息載體。根據這一點,可以把I/O設備當做文件來處理 。因此,與磁盤上的普通文件進行交互所用的同一系統調用可以直接用於I/O設備。這樣大大簡化了系統對不 同設備的處理,提高了效率。

Linux中的文件主要分為4種:普通文件、目錄文件、鏈接文件和設備文 件,如下圖:

內核如何區分和引用特定的文 件呢?這裡用到了一個重要的概念-------文件描述符。

在Linux中,所有對設備和文件的操作都是使 用文件描述符來進行的。文件描述符是一個非負的整數,它是一個索引值,並指向在內核中每個進程打開文件 的記錄表。當打開一個現存文件或創建一個新文件時,內核就向程返回一個文件描述符;當需要讀寫文件時, 也需要把文件描述符作為參數傳遞給相應的函數。(咱可以這樣理解,只有當對文件進行操作時,該文件才會 有文件描述符,進程沒有用到的文件統統不給描述符)

通常,一個進程啟動時,都會打開3個 文件:標准輸入、標准輸出和標准出錯處理。這3個文件分別對應描述符為0、1和2(也就是宏替換 STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO)。

基於文件描述符的I/O操作雖然不能直接移植到 類Linux以外的系統上(如Windows),但它往往是實現某些I/O操作的唯一途徑,如Linux中底層文件操作函數 (下邊會講)、多路I/O、TC[/IP套接字編程接口等、同時,它們也很好地兼容Posix標准,因此,可以很方便 地移植到任何Posix平台上。基於文件描述符的I/O操作是Linux中最常用的操作之一,下面就講講它。

底層文件I/O操作

這次主要介紹文件I/O操作的系統調用,主要用到5個函數:open()、read()、write ()、lseek()和close()。這些函數的特點不帶緩存,直接對文件(包括設備)進行讀寫操作。

1、基本 文件操作

函數說明

open()函數用於打開或創建文件,在打開或者創建文件時可以指定文件的屬 性及用戶的權限等各種參數。

close()函數用於關閉一個被打開的文件。當一個進程終止時,所有被它 打開的文件都由內核自動關閉,很多程序都使用這一功能而不顯示地關閉一個文件。

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

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

lseek()函數用於在指定的文件描述符 中將文件指針定位到相應的位置。每一個已打開的文件都有一個讀寫位置,當打開文件時,其讀寫位置通常指 向文件開頭;若是以附加的方式打開文件(如O_APPEND),則讀寫位置會指向文件尾。當read()或者write() 時,讀寫位置會隨之增加,lseek()便是用來控制該文件的讀寫位置的。它只能用在可定位(可隨機訪問)文 件操作中。管道、套接字和大部分字符設備文件是不可定位的,所以在這些文件的操作中無法使用lseek()調 用。

函數格式

下面我以表格的形式將這5個函數的格式寫出來,接下來再加上我的基礎實驗。

在open()函數中,flag參數可通過 “|” 組合構成,但前3個標志常量(O_RDONLY、O_WRONLY及O_RDWR) 不能相互組合。perms是文件的存取權限,既可以用宏定義表示法,也可以用八進制表示法。

在讀普通文件時,若讀到要求的字節數前已到達文件的尾部,則返回的字節數會小於希望讀書的字 節數。

關於size_t和ssize_t的區別,如果有不懂的請看: http://blog.csdn.net/mybelief321/article/details/8992052,也可以簡單的記住:ssize_t是有符號整形 ,size_t是無符號整形。

在寫普通文件時,寫操作從文件的當前指針位置開始。

下面是lseek較特別的使用

☆ 欲將讀寫位置移到文件開頭時:lseek(int fd,0,SEEK_SET)

☆ 欲將讀寫位置移到文件尾時:lseek(int fd,0,SEEK_END)

☆ 想要取得目前文件位置時:lseek(ind fd,0,SEEK_CUR)

注意:Linux系統不允許lseek()對tty裝置作用,此動作會令lseek()返回ESPIPE。

另外,其實還有一個文件創建函數creat(),它的函數原型是int creat(const char *pathname,int perms),它相當於使用下列的調用方式調用open():

open(const char *pathname, (O_CREAT|O_WRONLY|O_TRUNC));

基礎實驗1:

實驗說明:主要是為了演示open()函數的使用方 法。首先在自己的目錄下使用命令:vi open.c創建一個文件,如下圖,我在路徑/home/song/lianxi文件夾下 創建的:

然後編寫open.c文件內容,內 容如下:

編輯並保存open.c後的文件夾所含全部文件,如下:

使用命令:gcc open.c -o open編譯c文件,如下:

執行命令:./open 可以看到咱 們的實驗成功輸出了:

使用命令:more temp查看一下 temp的文件,裡邊有咱們使用write()寫的內容:

我將這個文件內容上傳到了: 點此下載,可以自行下載

基礎實驗2

實驗說明:基本功能是從一個文件(源文件)中讀取最後2KB數據並復制到另一個文件( 目標文件)。在實例中源文件是以只讀方式打開的,目標文件是以只寫方式(可以使讀/寫方式)打開的。若 目標文件不存在,可以創建並設置權限的初始值為644,即文件所有者可讀可寫,文件所屬組合其他用戶只能 讀。

首先先後使用命令:vi copy_file.c和 vi src.c 在自己的實驗目錄下創建文件,如下圖

然後再編輯copy_file.c的文件內容,如下

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<s ys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#define Buffer_Size 1024   /*每次讀寫緩存大小為1KB,大小不同,運行效率不同*/

#define Src_File_Name  "/home/song/lianxi/src.c"    /*源文件名,建議使用宏定義 */

#define Dest_File_Name "/home/song/lianxi/dest.c"      //目標文件 名*/

#define Offset     1024*2      //復制的數據大小,這裡為2KB*/

int main()

{

int src_fd,dest_fd;  /*文件描述符*/

unsigned char buff[Buffer_Size];   /*定義用於緩沖數據的數組*/

int real_read_len;     /*read()函數實際讀取到的字 節*/

/*以只讀方式打開源文件*/

src_fd=open(Src_File_Name,O_RDONLY);

/* 以只寫方式打開目標文 件,若此文件不存在則創建該文件,訪問權限為644*/

dest_fd=open (Dest_File_Name,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

/*如果打開文件出錯,則退出 程序*/

if(src_fd<0||dest_fd<0)

{
 printf("Open file error\n");
 exit(1);

}

/* 將源文件的讀/寫指針移到最後2KB的起始位置*/

lseek(src_fd,- Offset,SEEK_END);

/* 讀取源文件的最後2KB數據並寫到目標文件中,每次讀寫1KB*/

while ((real_read_len=read(src_fd,buff,sizeof(buff)))>0)

{
 write(dest_fd,buff,real_read_len);

}

/* 關閉文件,釋放資源*/

close (dest_fd);

close(src_fd);

return 0;

}

其中src.c的文件內容你可以自己隨便的放內容,但是要注意文件內容要大於2KB。

這兩個文件我 上傳到資源網站,可以自行下載:點此下載

編輯完之後,使用命令: gcc copy_file.c -o copy_file 編譯文件,然後執行命令:./copy_file,可以 看到自動生成了dest.c文件

使用命令:more dest.c可以看 到文件的內容

使用命令:ls -l dest.c可以看到該文件的大小正好為2KB(2048)

Copyright © Linux教程網 All Rights Reserved