系統(tǒng)之家 - 系統(tǒng)光盤下載網(wǎng)站!

當(dāng)前位置:系統(tǒng)之家 > 系統(tǒng)教程 > Linux中文件I/O操作

Linux下文件I/O操作的相關(guān)知識

時間:2014-12-26 15:58:35 作者:qipeng 來源:系統(tǒng)之家 1. 掃描二維碼隨時看資訊 2. 請使用手機(jī)瀏覽器訪問: https://m.xitongzhijia.net/xtjc/20141226/33535.html 手機(jī)查看 評論

  Linux文件I/O主要指的是文件的輸入輸出,很多初學(xué)者對文件的I/O不是很了解,Linux文件I/O的操作較多,下面小編就給大家詳細(xì)介紹下Linux文件I/O。

 Linux下文件I/O操作的相關(guān)知識

  linux 文件I/O教程(1)

  一,文件描述符

  對內(nèi)核而言,所以打開的文件都通過文件描述符引用。每個進(jìn)程都有一些與之關(guān)聯(lián)的文件描述符。文件描述符是一個非負(fù)整數(shù)。當(dāng)打開一個現(xiàn)有文件或創(chuàng)建一個新文件時,內(nèi)核向進(jìn)程返回一個文件描述符。當(dāng)讀或?qū)懸粋文件時,使用open或creat返回的文件描述符標(biāo)識該文件,將其作為參數(shù)傳送給read和write。

  一般有三個以及打開的文件描述符,他們是:

  代碼如下:

  0:標(biāo)準(zhǔn)輸入 STDIN_FILENO

  1:標(biāo)準(zhǔn)輸出 STDOUT_FILENO

  2標(biāo)準(zhǔn)錯誤輸出 STDERR_FILENO

  每行后面的符號常量是依從POSIX而定的。

  open函數(shù)

  代碼如下:

  #include 《sys/types.h》

  #include 《sys/stat.h》

  #include 《fcntl.h》

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

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

  pathname是要打開或創(chuàng)建文件的名字。

  flag用來定義打開文件所采取的的動作,必須調(diào)用以下模式之一

  O_RDONLY, O_WRONLY, O_RDWR分別代表只讀,只寫,讀寫方式打開。

  open還可以包括以下可選模式的組合

  O_APPEND:把寫入數(shù)據(jù)追加到文件的尾端

  O_CREAT:若文件不存在,則創(chuàng)建它。使用此選項(xiàng)時,需要第三個參數(shù)mode,用其指定該新文件的訪問權(quán)限。

  O_EXCL:如果同時指定了O_CREAT,而文件存在,則會出錯。用此可以測試一個文件是否存在,如果存在,則創(chuàng)建文件,這使測試和創(chuàng)建兩者成為一個原子操作。

  O_TRUNC: 如果此文件存在,而且為只寫或讀寫成功打開,則將其長度截為0。

  open返回的文件描述符一定是最小的未用描述符數(shù)值。這一點(diǎn)被某些應(yīng)用程序用在標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯誤輸出上。如,一個程序關(guān)閉了自己的標(biāo)準(zhǔn)輸出,然后再次調(diào)用open,文件描述符1就會被調(diào)用,并且標(biāo)準(zhǔn)輸出將被有效的重定向到另一個文件或設(shè)備。

  POSIX規(guī)范還標(biāo)準(zhǔn)化了一個creat調(diào)用,此函數(shù)等效于

  open(pathname,O_WONLY |O_CREAT | O_TRUNC, mode);

  close函數(shù)

  #include 《unistd.h》

  int close(int fd);

  close調(diào)用終止一個文件描述符fd與對應(yīng)文件之間的關(guān)聯(lián)。文件描述符被釋放后并能重新使用。close調(diào)用成功返回0,出錯返回-1.

  關(guān)閉一個文件時會釋放該進(jìn)程加在文件上的所有記錄鎖。當(dāng)一個進(jìn)程終止時,內(nèi)核自動關(guān)閉它所有打開的文件。

  lseek函數(shù)

  每個打開的文件都有一個與其相關(guān)聯(lián)的”當(dāng)前文件偏移量”。按系統(tǒng)默認(rèn)情況,當(dāng)打開一個文件時,除非指定O_APPEND選項(xiàng),否則該偏移量被設(shè)置為0。lseek可以為一個打開的文件設(shè)置偏移量。

  代碼如下:

  #include 《sys/types.h》

  #include 《unistd.h》

  off_t lseek(int fd, off_t offset, intwhence);

  offset用來指定位置,whence參數(shù)定義該偏移值的用法。whence可取以下值:

  代碼如下:

  SEEK_SET: The offset is set to offset bytes.

  SEEK_CUR: The offset is set to its current locationplus offset bytes.

  SEEK_END: The offset is set to the size of the fileplus offset bytes.

  成功調(diào)用返回從文件頭到文件指針被設(shè)置處的字節(jié)偏移值,失敗返回-1。參數(shù)offset定義在《sys/types.h》中。

  當(dāng)偏移量大于文件長度時,出現(xiàn)空洞,空洞不占用存儲區(qū)。

  read函數(shù)

  代碼如下:

  #include 《unistd.h》

  ssize_t read(int fd, void *buf, size_tcount);

  將與文件描述符fd關(guān)聯(lián)的文件中讀入count個字符放到buf中。返回讀入的字節(jié)數(shù),它可能小于請求的字節(jié)數(shù)。如果read調(diào)用返回0,就表示未讀入任何數(shù)據(jù),已到達(dá)了文件尾。返回-1,就表示出錯。

  write函數(shù)

  代碼如下:

  #include 《unistd.h》

  ssize_t write(int fd, const void *buf,size_t count);

  把緩沖區(qū)buf的前count個字節(jié)寫入與文件描述符fd相關(guān)聯(lián)的文件中。返回實(shí)際寫入的字節(jié)數(shù),通常與count值相同;否則表示出錯。出錯的一個常見原因是:磁盤已寫滿,或者超出了一個給定進(jìn)程的文件長度限制。

  實(shí)例:創(chuàng)建一個文件,寫入數(shù)據(jù),移動當(dāng)前偏移量,在讀數(shù)據(jù)。

  代碼如下:

  #include《unistd.h》 //《unistd.h》必須最早出現(xiàn),因?yàn)樗赡軙绊懙狡渌^文件。#include《stdio.h》

  #include《fcntl.h》

  #include《string.h》

  #include《errno.h》

  int main()

  {

  char* filename = “。//file”;

  char buf[100];

  char buf1[5];

  int fd;

  printf(“open a file to write\n”);

  if((fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ))==-1)

  {

  perror(“cannot open file\n”);

  return 1;

  }

  printf(“open file successfully!\n”);

  printf(“input a string:”);

  gets(buf);

  //write intofile

  if(write(fd,buf,strlen(buf)) !=strlen(buf))

  {

  perror(“cannot write intofile\n”);

  return 1;

  }

  close(fd);

  printf(“open file to read.\n”);

  if((fd=open(filename,O_RDONLY)) == -1)

  {

  perror(“cannot open thefile.\n”);

  return 1;

  }

  if(lseek(fd,3,SEEK_SET) == -1)

  {

  perror(“lseek erroe\n”);

  return 1;

  }

  //read from the file

  if(read(fd,buf1,4)==-1)

  {

  perror(“read error.\n”);

  return 1;

  }

  printf(“read from file is%s\n”,buf1);

  close(fd);

  return 0;

  }

  執(zhí)行與輸出結(jié)果:

  代碼如下:

  root@jb51:~$gcc -o io io.c

  root@jb51:~$./io

  open a file towrite

  open filesuccessfully!

  input a string:akxivbaslzkncxcasbxbwwvaidxbd

  open file toread.

  read from fileis ivba

  linux 文件I/O教程(2)

  下面介紹了linux中有關(guān)文件I/O的相關(guān)內(nèi)容,內(nèi)核使用三種數(shù)據(jù)結(jié)構(gòu)表示打開的文件,他們之間的關(guān)系決定了在文件共享方面一個進(jìn)程對另一個進(jìn)程可能產(chǎn)生的影響。

  一,文件共享

  內(nèi)核使用三種數(shù)據(jù)結(jié)構(gòu)表示打開的文件,他們之間的關(guān)系決定了在文件共享方面一個進(jìn)程對另一個進(jìn)程可能產(chǎn)生的影響。

  1) 每個進(jìn)程在進(jìn)程表中都有一個記錄項(xiàng),記錄項(xiàng)中包含一張打開文件描述表,可將其視為一個矢量,每個描述符占用一項(xiàng)。與每個文件描述符相關(guān)聯(lián)的是:

  a) 文件描述符標(biāo)志

  b) 指向一個文件表項(xiàng)的指針

  2) 內(nèi)核為所有打開文件維持一張文件表。每個文件表項(xiàng)包含:

  a) 文件狀態(tài)標(biāo)志(讀、寫、讀寫、添些、同步和阻塞等)

  b) 當(dāng)前文件偏移量

  c) 指向文件v節(jié)點(diǎn)表項(xiàng)的指針

  3) 每個打開文件(或設(shè)備)都有一個v節(jié)點(diǎn)(v-node)結(jié)構(gòu)。v節(jié)點(diǎn)包含了文件類型和對比文件進(jìn)行各種操作的函數(shù)的指針。對于大多數(shù)文件,v節(jié)點(diǎn)還包含了該文件的i節(jié)點(diǎn)。i節(jié)點(diǎn)包含文件所有者、文件長度、文件所在的設(shè)備、指向文件實(shí)際數(shù)據(jù)塊在磁盤上所在位置的指針等。

  打開文件的內(nèi)核數(shù)據(jù)結(jié)構(gòu)

  如果兩個進(jìn)程各自打開了同一個文件,則如圖2所示。假定第一個進(jìn)程在文件描述符3打開上該文件,而另一個進(jìn)程在文件描述符4上打開該文件。每個進(jìn)程都得得到一個文件表項(xiàng),但對一個給定的文件只有一個v節(jié)點(diǎn)表項(xiàng)。每個進(jìn)程都有自己的文件表項(xiàng)的一個理由是:使每個進(jìn)程都有自己對該問價的當(dāng)前偏移量。

  現(xiàn)在對前一節(jié)文件I/O(1)的幾個操作進(jìn)一步說明:

  1. 完成write之后,文件中當(dāng)前偏移量即所增加的字節(jié)數(shù)。如果當(dāng)前偏移量大于文件長度,則將i節(jié)點(diǎn)中當(dāng)前文件長度設(shè)為當(dāng)前文件偏移量。

  2. 用O_APPEND打開一個文件,相應(yīng)標(biāo)志會被設(shè)置到文件狀態(tài)標(biāo)識中。每次寫時,當(dāng)前偏移量會被設(shè)置為i節(jié)點(diǎn)中的文件長度

  3. lseek定位到文件尾端時,則文件當(dāng)前偏移量會被設(shè)置為當(dāng)前文件長度。

  可能有多個文件描述符指向同一文件表項(xiàng)。調(diào)用dup和fork時都能看到這一點(diǎn)。

  多個進(jìn)程讀同一文件能正確工作。但多個進(jìn)程寫同一文件時,可能產(chǎn)生預(yù)期不到的后果。可以利用原子操縱避免這種情況。

  原子操作

  一般而言,原子操作指的是由多部組成的操作。如果該院自地執(zhí)行,要么執(zhí)行完所以步驟,要么一步也不執(zhí)行。

  1. 添加至一個文件

  考慮一個進(jìn)程,它要講數(shù)據(jù)添加到一個文件尾端。早期UNIX不支持open,所以可以如下實(shí)現(xiàn):

  代碼如下:

  if(lseek(fd, 0L, 2)《0)

  err_sys(“lseekerror”);

  if(write(fd, buf, 100) != 100)

  err_sys(“writeerror”);

  對于單個進(jìn)程,這段程序能正常工作。但多個進(jìn)程就不一定。結(jié)社進(jìn)程A和B都對同一文件進(jìn)行添加操作。每個進(jìn)程都打開該文件,此時數(shù)據(jù)結(jié)構(gòu)之間關(guān)系如圖2中所示。假定A調(diào)用lseek,將A的當(dāng)前偏移量設(shè)置為1500。進(jìn)程B執(zhí)行l(wèi)seek也將其當(dāng)前偏移量設(shè)為1500。然后B調(diào)用write,將當(dāng)前偏移量增至1600。然后內(nèi)核又進(jìn)行進(jìn)程切換使進(jìn)程A恢復(fù)運(yùn)行,當(dāng)A調(diào)用write時,從其當(dāng)前偏移量1500處將數(shù)據(jù)寫入,將替換B剛寫入到該文件中的數(shù)據(jù)。

  問題出在邏輯操作“定位到文件尾端處,然后寫“使用了兩個分開的函數(shù)調(diào)用。解決辦法是使這兩個操作成為一個原子操作。O_APPEND標(biāo)識,使內(nèi)核每次對文件進(jìn)行寫之前,都將進(jìn)程當(dāng)前偏移量設(shè)置到該文件的尾端處。

  2.pread和pwrite函數(shù)

  原子性地定位搜索和執(zhí)行I/0。

  代碼如下:

  #include 《unistd.h》

  ssize_t pread(int fd, void *buf, size_tcount, off_t offset);

  ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset);

  ssize_t pread(int fd, void *buf, size_tcount, off_t offset);

  ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset);

  dup和dup2函數(shù)

  代碼如下:

  #include 《unistd.h》

  int dup(int oldfd);

  int dup2(int oldfd, int newfd);

  上面兩個函數(shù)都可用來復(fù)制一個現(xiàn)存的文件描述符。

  由dup返回的新文件描述符一定是當(dāng)前可用文件描述符中的最小數(shù)值。用dup2則可以用newfd參數(shù)指定新描述符的數(shù)值。如果newfd已經(jīng)打開,則先將其關(guān)閉。如果newfd等于oldfd,則dup2返回newfd而不關(guān)閉它。

  假定我們的進(jìn)程執(zhí)行了:

  newfd = dup(1);

  當(dāng)此函數(shù)執(zhí)行時,假設(shè)下一個可用的描述符是3。因?yàn)檫@兩個描述符指向同一個文件表項(xiàng),所以他們共享文件標(biāo)志以及同一文件偏移量。

  sync、fsync和fdatasync

  代碼如下:

  #include 《unistd.h》

  void sync(void);

  int fsync(int fd);

  int fdatasync(int fd);

  當(dāng)將數(shù)據(jù)寫入文件時,內(nèi)核通常將數(shù)據(jù)復(fù)制到一個緩沖區(qū),直到緩沖區(qū)寫滿,再將緩沖區(qū)排路輸出隊(duì)列,然后等待其到達(dá)隊(duì)首,才進(jìn)行實(shí)際的I/O操作。這種輸出防暑被稱為延遲寫。延遲寫減少了磁盤的讀寫次數(shù),但卻降低了文件內(nèi)容的跟新速度。當(dāng)系統(tǒng)發(fā)生故障時,延遲寫可能造成文件跟新內(nèi)容的丟失。為了保證磁盤上實(shí)際文件系統(tǒng)與緩沖區(qū)高速緩存中內(nèi)容一致性,UNIX系統(tǒng)提供了sync、fsync和fdatasync 三個函數(shù)。

  fcntl函數(shù)

  代碼如下:

  #include 《unistd.h》

  #include 《fcntl.h》

  int fcntl(int fd, int cmd, 。。。 /* arg */ );

  可以改變已經(jīng)打開文件的性質(zhì)。

  復(fù)制一個現(xiàn)有的描述符(cmd=F_DUPFD)

  獲得或設(shè)置文件描述符(cmd=F_GETFD|F_SETFD)

  獲得或設(shè)置文件狀態(tài)標(biāo)志(cmd=F_GETFL|F_SETFL)

  獲得或設(shè)置異步I/O所有權(quán)(cmd=F_GETOWN|F_SETOWN)

  獲得或設(shè)置記錄鎖(cmd=F_GETLK|F_SETLK、F_SETLKW)

  可以用fcntl函數(shù)設(shè)置文件狀態(tài),常用設(shè)置套接字描述符為非阻塞O_NONBLOCK

  ioctl函數(shù)

  #include 《sys/ioctl.h》

  int ioctl(int d, int request, 。。。);

  提供了一個用于控制設(shè)備及其描述符行為和配置底層服務(wù)的接口。

  /dev/fd

  打開文件/dev/fd/n等效于復(fù)制描述符n。

  上面就是Linux文件I/O的相關(guān)介紹了,通過這些介紹相信你已經(jīng)對文件I/O有了進(jìn)一步的了解,如果你還想了解更多的相關(guān)知識的話,不妨多多關(guān)注本網(wǎng)站吧。

標(biāo)簽 文件I/O

發(fā)表評論

0

沒有更多評論了

評論就這些咯,讓大家也知道你的獨(dú)特見解

立即評論

以上留言僅代表用戶個人觀點(diǎn),不代表系統(tǒng)之家立場

其他版本軟件

熱門教程

人氣教程排行

Linux系統(tǒng)推薦

官方交流群 軟件收錄