Linux下的C編程實戰之檔案系統編程 收藏

來源:互聯網
上載者:User

1.Linux檔案系統

  Linux支援多種檔案系統,如ext、ext2、minix、iso9660、msdos、fat、vfat、nfs等。在這些具體檔案系統的上層,Linux提供了虛擬檔案系統(VFS)來統一它們的行為,虛擬檔案系統為不同的檔案系統與核心的通訊提供了一致的介面。給出了Linux中檔案系統的關係:

 

  在Linux平台下對檔案編程可以使用兩類函數:(1)Linux作業系統檔案API;(2)C語言I/O庫函數。 前者依賴於Linux系統調用,後者實際上與作業系統是獨立的,因為在任何作業系統下,使用C語言I/O庫函數操作檔案的方法都是相同的。本章將對這兩種方法進行執行個體講解。

  2.Linux檔案API

  Linux的檔案操作API涉及到建立、開啟、讀寫和關閉檔案。

  建立

int creat(const char *filename, mode_t mode);

  參數mode指定建立檔案的存取許可權,它同umask一起決定檔案的最終許可權(mode&umask),其中umask代表了檔案在建立時需要去掉的一些存取許可權。umask可通過系統調用umask()來改變:

int umask(int newmask);

  該調用將umask設定為newmask,然後返回舊的umask,它隻影響讀、寫和執行許可權。

  開啟

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode); 

  open函數有兩個形式,其中pathname是我們要開啟的檔案名稱(包含路徑名稱,預設是認為在當前路徑下面),flags可以去下面的一個值或者是幾個值的組合:

標誌 含義
O_RDONLY 以唯讀方式開啟檔案
O_WRONLY 以唯寫的方式開啟檔案
O_RDWR 以讀寫的方式開啟檔案
O_APPEND 以追加的方式開啟檔案
O_CREAT 建立一個檔案
O_EXEC 如果使用了O_CREAT而且檔案已經存在,就會發生一個錯誤
O_NOBLOCK 以非阻塞的方式開啟一個檔案
O_TRUNC 如果檔案已經存在,則刪除檔案的內容
   

  O_RDONLY、O_WRONLY、O_RDWR三個標誌只能使用任意的一個。

  如果使用了O_CREATE標誌,則使用的函數是int open(const char *pathname,int flags,mode_t mode); 這個時候我們還要指定mode標誌,用來表示檔案的存取權限。mode可以是以下情況的組合:

標誌 含義
S_IRUSR 使用者可以讀
S_IWUSR 使用者可以寫
S_IXUSR 使用者可以執行
S_IRWXU 使用者可以讀、寫、執行
S_IRGRP 組可以讀
S_IWGRP 組可以寫
S_IXGRP 組可以執行
S_IRWXG 組可以讀寫執行
S_IROTH 其他人可以讀
S_IWOTH 其他人可以寫
S_IXOTH 其他人可以執行
S_IRWXO 其他人可以讀、寫、執行
S_ISUID 設定使用者執行ID
S_ISGID 設定組的執行ID

  除了可以通過上述宏進行“或”邏輯產生標誌以外,我們也可以自己用數字來表示,Linux總共用5個數字來表示檔案的各種許可權:第一位表示設定使用者ID;第二位表示設定組ID;第三位表示使用者自己的許可權位;第四位表示組的許可權;最後一位表示其他人的許可權。每個數字可以取1(執行許可權)、2(寫入權限)、4(讀許可權)、0(無)或者是這些值的和。例如,要建立一個使用者可讀、可寫、可執行,但是組沒有許可權,其他人可以讀、可以執行的檔案,並設定使用者ID位。那麼,我們應該使用的模式是1(設定使用者ID)、0(不設定組ID)、7(1+2+4,讀、寫、執行)、0(沒有許可權)、5(1+4,讀、執行)即10705:

open("test", O_CREAT, 10705); 

  上述語句等價於:

open("test", O_CREAT, S_IRWXU | S_IROTH | S_IXOTH | S_ISUID );

  如果檔案開啟成功,open函數會返回一個檔案描述符,以後對該檔案的所有操作就可以通過對這個檔案描述符進行操作來實現。

  讀寫

  在檔案開啟以後,我們才可對檔案進行讀寫了,Linux中提供檔案讀寫的系統調用是read、write函數:

int read(int fd, const void *buf, size_t length);
int write(int fd, const void *buf, size_t length);

  其中參數buf為指向緩衝區的指標,length為緩衝區的大小(以位元組為單位)。函數read()實現從檔案描述符fd所指定的檔案中讀取length個位元組到buf所指向的緩衝區中,傳回值為實際讀取的位元組數。函數write實現將把length個位元組從buf指向的緩衝區中寫到檔案描述符fd所指向的檔案中,傳回值為實際寫入的位元組數。

  以O_CREAT為標誌的open實際上實現了檔案建立的功能,因此,下面的函數等同creat()函數:

int open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); 

  定位

  對於隨機檔案,我們可以隨機的指定位置讀寫,使用如下函數進行定位:

int lseek(int fd, offset_t offset, int whence);

  lseek()將檔案讀寫指標相對whence移動offset個位元組。操作成功時,返迴文件指標相對於檔案頭的位置。參數whence可使用下述值:

  SEEK_SET:相對檔案開頭
  SEEK_CUR:相對檔案讀寫指標的當前位置
  SEEK_END:相對檔案末尾

  offset可取負值,例如下述調用可將檔案指標相對當前位置向前移動5個位元組:

lseek(fd, -5, SEEK_CUR);

  由於lseek函數的傳回值為檔案指標相對於檔案頭的位置,因此下列調用的傳回值就是檔案的長度:

lseek(fd, 0, SEEK_END);

  關閉

  當我們操作完成以後,我們要關閉檔案了,只要調用close就可以了,其中fd是我們要關閉的檔案描述符:

int close(int fd);

  常式:編寫一個程式,在目前的目錄下建立使用者可讀寫檔案“hello.txt”,在其中寫入“Hello, software weekly”,關閉該檔案。再次開啟該檔案,讀取其中的內容並輸出在螢幕上。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define LENGTH 100
main()
{
 int fd, len;
 char str[LENGTH];
 fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 建立並開啟檔案 */
 if (fd)
 {
  write(fd, "Hello, Software Weekly", strlen("Hello, software weekly")); /* 寫入 Hello, software weekly字串 */
  close(fd);
 }

 fd = open("hello.txt", O_RDWR);
 len = read(fd, str, LENGTH); /* 讀取檔案內容 */
 str[len] = '\0';
 printf("%s\n", str);
 close(fd);
}

  編譯並運行,執行結果如:

 

  3.C語言庫函數

  C庫函數的檔案操作實際上是獨立於具體的作業系統平台的,不管是在DOS、Windows、Linux還是在VxWorks中都是這些函數:

  建立和開啟

FILE *fopen(const char *path, const char *mode);

  fopen()實現開啟指定檔案filename,其中的mode為開啟模式,C語言中支援的開啟模式如下表:

標誌 含義
r, rb 以唯讀方式開啟
w, wb 以唯寫方式開啟。如果檔案不存在,則建立該檔案,否則檔案被截斷
a, ab 以追加方式開啟。如果檔案不存在,則建立該檔案
r+, r+b, rb+ 以讀寫方式開啟
w+, w+b, wh+ 以讀寫方式開啟。如果檔案不存在時,建立新檔案,否則檔案被截斷
a+, a+b, ab+ 以讀和追加方式開啟。如果檔案不存在,建立新檔案

  其中b用於區分二進位檔案和文字檔,這一點在DOS、Windows系統中是有區分的,但Linux不區分二進位檔案和文字檔。

  讀寫

  C庫函數支援以字元、字串等為單位,支援按照某中格式進行檔案的讀寫,這一組函數為:

int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
char *fgets(char *s, int n, FILE *stream);
int fputs(const char *s, FILE *stream);
int fprintf(FILE *stream, const char *format, ...);
int fscanf (FILE *stream, const char *format, ...);
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream);

  fread()實現從流stream中讀取加n個欄位,每個欄位為size位元組,並將讀取的欄位放入ptr所指的字元數組中,返回實際已讀取的欄位數。在讀取的欄位數小於num時,可能是在函數調用時出現錯誤,也可能是讀到檔案的結尾。所以要通過調用feof()和ferror()來判斷。

  write()實現從緩衝區ptr所指的數組中把n個欄位寫到流stream中,每個欄位長為size個位元組,返回實際寫入的欄位數。

  另外,C庫函數還提供了讀寫過程中的定位能力,這些函數包括

int fgetpos(FILE *stream, fpos_t *pos);
int fsetpos(FILE *stream, const fpos_t *pos);
int fseek(FILE *stream, long offset, int whence);
等。

  關閉

  利用C庫函數關閉檔案依然是很簡單的操作:

int fclose (FILE *stream);

  常式:將第2節中的常式用C庫函數來實現。

#include <stdio.h>
#define LENGTH 100
main()
{
 FILE *fd;
 char str[LENGTH];

 fd = fopen("hello.txt", "w+"); /* 建立並開啟檔案 */
 if (fd)
 {
  fputs("Hello, Software Weekly", fd); /* 寫入Hello, software weekly字串 */
  fclose(fd);
 }

 fd = fopen("hello.txt", "r");
 fgets(str, LENGTH, fd); /* 讀取檔案內容 */
 printf("%s\n", str);
 fclose(fd);
}

  4.小結

  Linux提供的虛擬檔案系統為多種檔案系統提供了統一的介面,Linux的檔案編程有兩種途徑:基於Linux系統調用;基於C庫函數。這兩種編程所涉及到檔案操作有建立、開啟、讀寫和關閉,對隨機檔案還可以定位。本章對這兩種編程方法都給出了具體的執行個體。

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/yangdelong/archive/2010/04/13/5480837.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.