APUE文件io

第三章 文件i/o

3.1引言

  • 不帶緩沖的io(unix系統(tǒng)在內(nèi)核中設(shè)有緩沖區(qū),這個不帶緩沖意思是用戶不自己緩沖)
    • 每個read和write都調(diào)用內(nèi)核中的一個系統(tǒng)調(diào)用

3.2 文件描述符

  • 對于內(nèi)核而言盯桦,所有打開的文件都通過文件描述符引用,是一個非負(fù)整數(shù)肥卡。打開或創(chuàng)建一個文件的時候事镣,內(nèi)核返回一個文件描述符揪胃。
  • UNIx系統(tǒng)shell把文件描述符0與進(jìn)程的標(biāo)準(zhǔn)輸入關(guān)聯(lián)氛琢,文件描述符1與標(biāo)準(zhǔn)輸出關(guān)聯(lián),文件描述符與標(biāo)準(zhǔn)錯誤關(guān)聯(lián)阳似。

3.3函數(shù)open和openat

  • 調(diào)用這個兩個函數(shù)可以打開一個文件
    #include <fcntl.h>
    
    int open(const char *path, int oflag,.../ *mode_t mode */) ;
    int openat(int fd, const char *path, int oflag,.../ *mode_t mode */) ;
                // 成功返回文件描述符,失敗返回-1
                //path表示文件路勁
  • oflag參數(shù)可以使用下面的常量進(jìn)行或運算構(gòu)成oflag參數(shù)

    • O_RDONLY //只讀打開 0
    • O_WRONLY //只寫打開 1
    • O_RDWR //讀寫打開 2
    • O_EXEC //只執(zhí)行打開
    • O_SEARCH //只搜索打開
    • O_APPEND //寫時追加
    • O_CLOEXEC //把FD_CLOEXEC 常量設(shè)置為文件描述符的標(biāo)志
    • O_CREAT //若此文件不存在則創(chuàng)建它
    • O_DIRECTORY //如果path引用的不是目錄俏讹,則出錯
    • O_EXCL //如果同時制定了O_CREAT畜吊,而文件已經(jīng)存在,則出錯殉疼,可以用此測試文件是否存在
    • O_NOCTTY //如果path引用的時終端設(shè)備捌年,則不將該設(shè)備分配作為此進(jìn)程的控制終端
    • O_NOFOLLOW //如果path引用的時一個符號鏈接,則出錯
    • O_NONBLOCK //如果path引用的是一個FIFO礼预,塊設(shè)備或字符文件,則設(shè)置為非阻塞i/o
    • O_SYNC //每次write都等待物理i/o操作完成
    • O_TRUNC //如果文件存在荠藤,而且為制度或讀寫成功打開获高,則將其長度截斷為0
    • O_TTY_INIT //如果打開一個還未打開的終端設(shè)備,設(shè)置非標(biāo)準(zhǔn)termios的參數(shù)值念秧,使其符合sus
    • O_DSYNC //使每次write都要等待物理i/o操作完成
    • O_RSYNC // 使每一個以文件描述符作為參數(shù)進(jìn)行的read操作等待,直至所有對文件同一部分掛起的寫操作完成
  • 由open和openat返回的文件描述符一定是最小的未用文件描述符數(shù)值币狠。

  • fd參數(shù)把open和openat參數(shù)區(qū)分開砾层,共有三種可能性

    • path時絕對路徑名,這種情況忽略fd參數(shù)肛炮,openat相當(dāng)于openat
    • path參數(shù)指定的時相對路徑名宝踪,fd參數(shù)指出相對路勁名的開始地址碍扔,fd參數(shù)是通過打開相對路徑名所在的目錄來獲取的
    • path參數(shù)制定了相對路徑名,fd參數(shù)具有特殊值A(chǔ)T_FDCWD厉膀,這種情況下二拐,路徑名在當(dāng)前工作目錄中獲取,openat函數(shù)在操作上與open函數(shù)一致
  • openat()是在新增的一類函數(shù)之一希望解決兩個問題:

    • 讓線程可以使用相對路徑名打開目錄中的文件卓鹿,而不再只能打開當(dāng)前工作目錄
    • 可以避免time-of-check-to-time-of-use(TOCTTOU) 錯誤
  • 文件名和路徑名截斷

    • 如何找到一個系統(tǒng)的NAME_MAX
      • 使用sysconf函數(shù)和pathconf,fpathconf函數(shù),通過傳遞name參數(shù)來獲得系統(tǒng)的各個限制值
    • 如果NAME_MAX是14,我們試圖再當(dāng)前目錄中創(chuàng)建一個文件名15的新文件杰妓,則會發(fā)生什么碘勉?
      • 不同系統(tǒng)對該種情況有不同的反應(yīng)

3.4 函數(shù)creat

#include <fcntl.h>
int create(const char *path, mode_t mode) ;
    //返回值;若成功验靡,返回為只寫打開的fd,出錯-1
    //這個函數(shù)等效于
    open(path,O_WRONLY|O_CREAT|O_TRUNC高职,mode) ;
  • creat函數(shù)的不足之處時它以只寫的方式打開所創(chuàng)建的文件

3.5 函數(shù)close

#include <fcntl.h>
int close(int fd) ;
  • 關(guān)閉一個文件還會釋放該進(jìn)程加載該文件上的所有記錄鎖

3.6 函數(shù)lseek

  • 每個打開文件都有一個與其相關(guān)的當(dāng)前文件偏移量(current file offset)辞州,用以度量從文件開始處計算的字節(jié)數(shù)。
  • 通常讀寫操作都是從當(dāng)前文件偏移量開始变过,并使偏移量增加所讀寫的字節(jié)數(shù)
  • 系統(tǒng)默認(rèn)的情況,打開一個文件時岛杀,除非指定O_APPEND選項崭孤,否則偏移量設(shè)為0
  • 可以顯示的調(diào)用lseek為打開的文件設(shè)置偏移量
#include <fcntl.h>
off_t lseek(int fd, off_t offset, int whence);
    //成功返回新的偏移量糊肠,出錯返回-1
  • 對于參數(shù)offset的值的解釋和whence的值有關(guān)
    • 如果whence時SEEK_SET土浸,則該文件的偏移量設(shè)置為據(jù)文件開始處offset字節(jié)
    • 如果whence時SEEK_CUR,則該文件的偏移量設(shè)置為當(dāng)前值加offset黄伊,offset可正可負(fù)
    • 如果whence時SEEK_END,則該文件的偏移量設(shè)置為據(jù)文件長度加offset字節(jié)墓阀,offset可正可負(fù)
  • 若lseek成功執(zhí)行拓轻,則返回新的文件偏移量,為此可用下列的方式打開文件偏移量
off_t currpos ;
currops = lseek(fd, 0, SEEK_CUR) ;

上面的方法也可以用來判斷涉及的文件是否可以設(shè)置偏移量

  • lseek僅當(dāng)當(dāng)前文件偏移量記錄都在內(nèi)核中扶叉,并不引起I/O操作枣氧,然后偏移量被用于下一個讀寫操作
  • 文件偏移量可以大于文件長度,對該文件的下一次寫將加長該文件并形成一個空洞达吞,位于文件中但是沒有寫過的字節(jié)都被讀為0
  • 文件空洞不要求在磁盤上占用存儲區(qū),具體處理方式和文件系統(tǒng)有關(guān)
  • 因為lseek使用的偏移量是用offset表示的吞鸭,所以允許具體實現(xiàn)根據(jù)各自特定平臺自行選擇大小合適的數(shù)據(jù)類型覆糟。

3.7 函數(shù)read

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes) ;        //void * 表示通用指針
    //返回:讀到的字節(jié)數(shù),若已到文件尾搪桂,返回0,出錯返回-1
  • 有多種情況可以使讀到的字節(jié)數(shù)少于要求讀的字節(jié)數(shù)
    • 讀普通文件時酗电,讀到文件要求的字節(jié)數(shù)前已經(jīng)到達(dá)文件尾端
    • 當(dāng)從終端設(shè)備讀時内列,通常一次最多讀一行
    • 當(dāng)從網(wǎng)絡(luò)讀時,網(wǎng)絡(luò)中的緩沖區(qū)機(jī)制可能造成返回值小于要求讀的字節(jié)數(shù)
    • 當(dāng)從管道和FIFO讀時话瞧,如果管道包含的字節(jié)少于所需的數(shù)量寝姿,那么read將只返回實際可用的字節(jié)數(shù)
    • 當(dāng)一信號中斷划滋,而已經(jīng)讀了的部分?jǐn)?shù)據(jù)量時
  • 讀操作從文件的當(dāng)前偏移量處開始,在成功返回之前根资,該偏移量將增加時機(jī)讀到的字節(jié)數(shù)

3.8 函數(shù)write

    #Include  <unistd.h>
    
    ssize_t write(int fd, const void *buf, size_t nbytes) ;
    //成功返回已寫的字節(jié)數(shù)同窘,出錯返回-1
  • 返回值通常和nbytes的值相同,否則意味著出錯
  • write出錯的常見原因是磁盤已經(jīng)滿了想邦,或者超過了一個給定進(jìn)程的文件長度限制
  • 對于普通文件,寫操作從文件的當(dāng)前偏移量開始鹰椒,如果在打開該文件時制定了O_APPEND選項呕童,則每次都將文件偏移量移到末尾
  • 一次成功寫,offset增加實際寫的字節(jié)數(shù)

3.9 I/O的效率

  • 當(dāng)緩沖區(qū)長度為4096的時候,繼續(xù)增加緩沖區(qū)長度對程序的用戶cpu時間幾乎沒有影響了(應(yīng)該和i/o的接口讀取速率有關(guān))
  • 大多數(shù)文件系統(tǒng)為了改善性能采取了預(yù)讀技術(shù)
  • 預(yù)讀就是當(dāng)檢測到正在順序讀的時候套蒂,系統(tǒng)就試圖讀取比應(yīng)用所要求的更多的數(shù)據(jù)

3.10 文件共享

  • unxi系統(tǒng)支持在不同進(jìn)程之間共享文件
  • 內(nèi)核使用三種數(shù)據(jù)結(jié)構(gòu)表示打開的文件
    • 每個進(jìn)程在進(jìn)程表項中都有一個記錄項,記錄項中包含一張打開的文件描述符表
    • 文件表項 :內(nèi)核為所有打開的文件按維持一張文件表烁挟,每個表項包含如下幾項
      • 當(dāng)前文件狀態(tài)標(biāo)志(讀骨坑,寫,追加欢唾,。斑芜。祟霍。)
      • 當(dāng)前文件偏移量
      • 指向該文件v-node表象的指針
    • 每個打開文件都有一個v-node結(jié)構(gòu)(linux下的i-node)盈包,包含文件類型和對此文件進(jìn)行各種操作的函數(shù)的指針
      • 大多數(shù)文件的v-node還包含該文件的i-node醇王,這些信息時在打開文件的受從磁盤讀入內(nèi)存的
  • 如果一個文件被多個進(jìn)程打開,打開該文件的每個進(jìn)程都獲得一個文件表項叛氨,并且每個進(jìn)程有自己的文件偏移量

3.11 原子操作

  1. 追加到一個文件
  • 原子操作為了避免先對文件進(jìn)行偏移量設(shè)置根暑,但是該進(jìn)程被內(nèi)核換下,然后另外一個對該偏移量進(jìn)行了重新設(shè)置排嫌,導(dǎo)致切到原先進(jìn)程的時候出現(xiàn)偏移量的錯誤。會出現(xiàn)數(shù)據(jù)覆蓋之類的情況
  • 使用O_APPEND怖糊,在每次寫之前颇象,都會將文件偏移量放到最后
  1. 函數(shù)pread和pwrite
  2. 創(chuàng)建一個文件
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset) ;
 #成功返回讀到的字節(jié)數(shù)出錯返回-1
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset) ;
 # 成功返回已寫的字節(jié)數(shù),出錯返回-1
  • 原子操作指的是多步組成的一個操作扰魂,如果該操作執(zhí)行蕴茴,要么全部都執(zhí)行完,要么一步都不執(zhí)行倦淀,不能只執(zhí)行其中的一步

3.12 函數(shù)dup和dup2

復(fù)制現(xiàn)有文件描述符

int dup(int fd) ; //返回新文件描述符時當(dāng)前可用文件描述符中最小值
int dup2(int fd, int fd2) ; //fd2可以指定新描述符的值。

3.13 函數(shù)sysnc姻成,fsync和fdatasysnc

  • 延遲寫:當(dāng)我們向文件寫數(shù)據(jù)時愿棋,內(nèi)核通常先將數(shù)據(jù)復(fù)制到緩沖區(qū)中,然后排入隊列初斑,晚些時候在寫入磁盤
  • 通常,當(dāng)內(nèi)核需要重用緩沖區(qū)來存放其他磁盤塊數(shù)據(jù)時候砂竖,它會把所有延遲寫數(shù)據(jù)塊寫入磁
  • 為了保證磁盤上時機(jī)文件系統(tǒng)和緩沖區(qū)中內(nèi)容的一致性,unix系統(tǒng)提供了以下三個函數(shù)
  • update系統(tǒng)守護(hù)進(jìn)程周期性的調(diào)用sync函數(shù)突硝,定期(大約30s)flush緩沖區(qū)置济。
#include <unistd.h>

int fsync(int fd) ; //只對由文件描述符fd指定的一個文件起作用,等待寫磁盤結(jié)束后返回浙于,一般用于數(shù)據(jù)庫
int fdatasync(int fd) ; //類似于fsync,只影響文件的數(shù)據(jù)部分腐宋。

void sync(void) ;   //將所有修改過的塊緩沖區(qū)排入寫隊列檀轨,然后返回,實際上并不等待寫磁盤結(jié)束

3.14 函數(shù)fcntl

可以改變已經(jīng)打開文件的屬性

    int fcntl(int fd, int cmd, ...//int arg);
  • 第三個參數(shù)是指向一個結(jié)構(gòu)的指針
  • fcntl函數(shù)有一下幾個功能
    • 復(fù)制一個已有文件描述符(cmd=FDUPFD 或FDUPFD_CLOEXEC)
    • 獲取/設(shè)置文件描述符標(biāo)志(cmd=F_GETFD/FSETFD)
    • 獲取/設(shè)置文件狀態(tài)(cmd=GETFL/SETFL)
    • 獲取/設(shè)置異步i/o所有權(quán)(cmd=F_GETOWN/SETOWN)
    • 獲取設(shè)置記錄鎖(cmd=F_GETLK,F_SETLK/F_SETLKW)
      -每個cmd的意思
    • F_DUPFD
      • 復(fù)制文件描述符fd
    • F_DUPFD_CLOEXEC
      • 復(fù)制文件描述符卫枝,設(shè)置與新文件描述符關(guān)聯(lián)的FD_CLOEXEC文件描述符值讹挎,返回新文件描述符
    • F_GETFD
      • 對于fd的文件描述符標(biāo)志作為函數(shù)值返回
    • F_SETFD
      • 對于fd設(shè)置文件描述符標(biāo)志
    • F_GETFD
      • 對應(yīng)于fd的文件狀態(tài)標(biāo)志作為函數(shù)值返回。
    • F_SETFL
      • 將文件狀態(tài)標(biāo)志設(shè)置為第三個參數(shù)的值
    • F_GETOWN
      • 獲取當(dāng)前SIGIO和SIGURG信號的進(jìn)程ID或進(jìn)程組id筒溃。

3.16 /dev/fd

較新的系統(tǒng)都提供名為/dev/fd的目錄铡羡,其目錄項為0意鲸,1,2怎顾,等的鏈接文件,打開文件/devfd/n等效于復(fù)制描述符n

第四章 文件和目錄

4.1 引言

文件系統(tǒng)的其他特征和文件的性質(zhì)夭委,屬性

4.2 函數(shù)stat募强,fstat崇摄,fstatat和lstat

#include <sys/stat.h>

int stat(const char *restrict pathname, struct stat *restrict buf) ;
int fstat(int fd, struct stat *buf) ;
int lstat(const char * restrict pathname, struct stat * restrict buf) ;
int fstatat(int fd, const char *restarict pathname, stuct stat * restrict buf ,int flag)

這些stat用于返回文件有關(guān)的信息結(jié)構(gòu)慌烧。

  • 同時stat也是一個結(jié)構(gòu)體,用于保存文件的一些信息

4.3文件類型

  • 普通文件
  • 目錄文件
    • 只有內(nèi)核能寫
  • 塊設(shè)備文件
  • 字符設(shè)備文件
    • 提供對設(shè)備不帶緩沖的訪問
  • fifo
    • 用于ipc
  • socket
    • 用于進(jìn)程網(wǎng)絡(luò)間通信
  • 符號鏈接
    • 指向另一個文件
// 測試文件屬性
#include <iostream>
#include "apue.h"
#include <dirent.h>
#include <fcntl.h>

int main(int argc, char * argv[]) {

   int i ;
   struct  stat buf ;
   char *ptr ;
   for (i=1;i<argc;i++){
       printf(argv[i]);
       if (lstat(argv[i],&buf)<0){
           printf("lstat error");
           continue ;
       }
       if (S_ISREG(buf.st_mode))
            printf("regular") ;
       else if(S_ISDIR(buf.st_mode)){
           ptr = "directory" ;
       }else if(S_ISCHR(buf.st_mode)){
           ptr = "directory" ;
       }else if(S_ISBLK(buf.st_mode)){
           ptr = "directory" ;
       }else if(S_ISFIFO(buf.st_mode)){
           ptr = "directory" ;
       }else if(S_ISLNK(buf.st_mode)){
           ptr = "directory" ;
       }else if(S_ISSOCK(buf.st_mode)){
           ptr = "directory" ;
       } else
           ptr = "unkonw mode";
       printf("%s \n", ptr) ;
   }

   return 0;
}

4.4 設(shè)置用戶id和設(shè)置組id

  • 每個文件有三類id
    • 實際用戶id--------標(biāo)志我們是誰(標(biāo)記操作的用戶)
    • 有效用戶id--------標(biāo)識用于文件訪問權(quán)限檢查
    • 設(shè)置用戶id--------用于exec函數(shù)保存
  • 通常uid=有效用戶id
  • st_mode(stat中的一項)中可以設(shè)置一個特殊標(biāo)志厕氨,含義時當(dāng)執(zhí)行這個文件的時候汹粤,將進(jìn)程的有效用戶id者之謂文件所有者的用戶id----set_ser_ID
  • 還可以將執(zhí)行此文件的進(jìn)程的有效組id設(shè)置為文件所有組的id -----set-groups-ID
  • 如果文件按所有者時超級用戶權(quán)限,而且設(shè)置了該文件的設(shè)置用戶id位国葬,那么當(dāng)該程序文件執(zhí)行的時候遭京,該進(jìn)程具有root權(quán)限,不管執(zhí)行該程序的時機(jī)用戶id是多少

4.5 文件訪問權(quán)限

  • 所有的文件類型都有權(quán)限
  • 權(quán)限有讀寫執(zhí)行三種
  • 三種權(quán)限的使用方式如下
    • 當(dāng)用名字打開任一類型文件時船殉,對該名字中包含的每個目錄斯嚎,都應(yīng)具有執(zhí)行權(quán)限
      • 對目錄的讀權(quán)限,允許我們讀目錄堡僻,獲得目錄中的文件名列表(可以ls不能cd)
    • 對一個文件的讀/寫權(quán)限決定我們是否能夠打開現(xiàn)有文件進(jìn)行讀/寫操作
    • 在一個目錄中創(chuàng)建文件,必須對該目錄有執(zhí)行和寫權(quán)限
    • 為了刪除現(xiàn)有文件硼讽,必須有 x w牲阁,對該文件本身不需要有x w
    • 如果用7各exec函數(shù)終端額任何一個執(zhí)行文件,都必須對該文件具有執(zhí)行權(quán)限
  • 進(jìn)程每次操作文件會進(jìn)行權(quán)限測試城菊,測試一般使用有效用戶id

4.6 新文件和目錄的所有權(quán)

  • 新文件的用戶id設(shè)置為進(jìn)程的有效用戶id
  • 關(guān)于組id
    • 可以時進(jìn)程有效組id
    • 可以時所在目錄的組id

4.7 函數(shù)access和faccessat

access和faccessat按照實際用戶id和實際組id進(jìn)行訪問權(quán)限測試

#include<unistd.h

int access(const char *pathname, int mode) ;
int faccessat(int fd, const char *pathname, int mode, int flag );
        //mode 可為讀寫執(zhí)行 R_OK,W_OK,X_OK
        //成功返回0凌唬,否則返回-1
  • flag參數(shù)用于改變faccessat 的行為,如果flag設(shè)置為AT_EACCESS,訪問檢查用的時調(diào)用進(jìn)程的有效用戶id和有效組id

4.8 函數(shù)umask

  • umask函數(shù)為進(jìn)程設(shè)置文件模式創(chuàng)建屏蔽字,并返回之前的值(umask設(shè)置文件創(chuàng)建時的默認(rèn)權(quán)限撕贞,與chmod的效果剛好相反窝剖,==umask設(shè)置的是權(quán)限“補(bǔ)碼”==,)
#include <sys/stat.h>
mode_t umask(mode_t cmask) ;
    //返回值赐纱,之前的文件模式創(chuàng)建屏蔽字
  • c-mask時圖4.6中列出的9各常量

4.9 函數(shù)chmod疙描,fchmod,fchmodat

  • 更改現(xiàn)有文件訪問權(quán)限
    #include<sys/stat.h>
    int chmode(const char *pathname, mode_t mode) ; //在指定文件上操作
    int fchmod(int fd,  mode_t mode) ;//對已經(jīng)打開的文件操作
    int fchmodat(int fd, const char * pathname, mode_t mode, int flag); //上面兩個的融合
    //成功返回0起胰,失敗返回-1
  • flag 參數(shù)可以用于改變fchmodat的行為,當(dāng)設(shè)置了
  • mode是各種常量的按位或

4.10 粘著位 -----S_ISVTX

  • 如果對一個目錄設(shè)置了粘著位地消,只有對該目錄具有寫權(quán)限的用戶并且滿足下列條件之一畏妖,才能刪除或重命名該目錄下的文件
    • 擁有該文件
    • 擁有此目錄
    • 是超級用戶

4.11 函數(shù)chown,fchown戒劫,fchownat和lchown

#include<unistd.h>
int chown(const char * pathname, uid_t owner, gid_t group) 
int fchown(int fd, uid_t owner, gid_t group) 
int fchownat(int fd, const char *pathname, uid_t owner, gid_t group, int flag)
int lchown(const char * pathname, uid_t owner ,gid_t group)
  • lchown和fchown(設(shè)置了AT_SYMLINK_NOFOLLOW)更改符號鏈接本身的所有者
  • BSD的系統(tǒng)只有超級用戶才能更改一個文件的所有者

4.12 文件長度

  • stat結(jié)構(gòu)成員st_size表示以字節(jié)為單位的文件的長度
  • 文件空洞
    • 文件空洞由偏移量超過文件尾部后寫入數(shù)據(jù)造成

4.13 文件截斷

  • 需要在文件末尾截去一些數(shù)據(jù)以縮短文件
  • 打開文件的時候?qū)_TRUNC標(biāo)志可以做到這一點
//將一個現(xiàn)有文件截為length
#Include <unistd.h>
int truncate(const char * pathname, off_t length )
int ftruncate(int fd, off_t length)
    //成功返回0迅细,出錯返回-1

4.14 文件系統(tǒng)

  • i-node 包含文件相關(guān)的所有信息:文件類型,文件訪問權(quán)限位茵典,文件長度,指向文件數(shù)據(jù)塊的指針枚尼,stat結(jié)構(gòu)的大多數(shù)信心取自i-node
  • mv命令構(gòu)造一個新的i-node的目錄項砂吞,然后刪除老的目錄項

4.15 函數(shù)link崎溃,linkat,unlink概而,unlinkat和remove

#indlude <unistd.h>
int link(const char *existingpath, const char *newpath)
int linkat(int efd, const char *existingpath, int nfd, const char * newpath, int flag)

4.16 函數(shù)rename和renameat


第5章 標(biāo)準(zhǔn)i/o庫

5.1 引言

  • 令人驚訝的是,35年來赎瑰,幾乎沒有對標(biāo)準(zhǔn)io庫進(jìn)行修改

5.2 流和FILE對象

  • 對于I/O函數(shù)都是圍繞文件描述符的
  • 對于標(biāo)準(zhǔn)I/O庫,所有的操作都是圍繞流進(jìn)行的压储,當(dāng)用標(biāo)準(zhǔn) I/O打開或創(chuàng)建文件的時候源譬,我們已經(jīng)使一個流和一個文件相關(guān)聯(lián)
  • 流的定向決定了所讀寫的流使單字節(jié)的還是多字節(jié)(寬)字符的
  • 當(dāng)流創(chuàng)建時為定向,對一個流使用單/多字節(jié)I/O函數(shù)踩娘,則該流被設(shè)置為相應(yīng)的長度定向
  • 只有兩個函數(shù)可以改變流的定向养渴,freopen和fwide
    • freopen用于清楚流的定向
    • fwide用于設(shè)置流的定向
# include<stdio.h>
#include<wchar.h>
int fwide(FILE *fp, int mode) ;
    //返回值,若流為寬定向理卑,返回正值,字節(jié)定向返回負(fù)值霞溪,未定項返回0
  • fwide不該變流的定向中捆,無出錯返回
  • 打開一個流的時候,返回一個指向FILE結(jié)構(gòu)的指針殴蓬,該指針包含所有流的信息蟋滴,該指針也稱為==文件指針==

5.3 標(biāo)準(zhǔn)輸入,輸出津函,錯誤

  • 對一個進(jìn)程預(yù)定義了這三個流,通過預(yù)定義文件指針stdin涩馆,stdout,stderr加以引用

5.4 緩沖

  • 標(biāo)準(zhǔn)io提供緩沖的目的時盡可能少使用read魂那,write.它對每個流進(jìn)行自動的緩沖管理

  • 標(biāo)準(zhǔn)io提供一下三種緩沖

    • 全緩沖
      • 填滿緩沖區(qū)后才進(jìn)行實際io操作涯雅,駐留磁盤文件按通常全緩沖
      • flush說明標(biāo)準(zhǔn)io進(jìn)行緩沖區(qū)的清洗操作,可由標(biāo)準(zhǔn)io自動沖洗
      • 調(diào)用fflush可以手動沖洗
    • 行緩沖
      • 在輸入輸出遇到換行符的受進(jìn)行io操作
      • 行緩沖的限制
        • 標(biāo)準(zhǔn)io提供的行緩沖區(qū)時固定長度活逆,填滿緩沖區(qū)時沒有換行符也進(jìn)行io操作
        • 當(dāng)從一個不帶緩沖的流或一個行緩沖流得到輸入數(shù)據(jù),就會重復(fù)所有行緩沖流
    • 不緩沖
      • 不對字符進(jìn)行緩沖存儲
      • 標(biāo)準(zhǔn)錯誤不緩沖
  • 對任何一個給定的流贬养,如果我們不喜歡這些系統(tǒng)默認(rèn)琴庵,那么我們可以更改緩沖類型

//打開或關(guān)閉緩沖機(jī)制
void setbuf(FILE *restrict fp, char *restrict buf) ;    
//設(shè)置緩沖類型 
int setvbuf(FILE *restrict fp, char * restrict buf, int mode, size_t size) ;  
                                //成功返回0,錯誤返回-1
  • 上面的操作在流已被打開且應(yīng)在操作流之前調(diào)用
  • 使用vsetbuf可以精確說明緩沖類型
    • _IOFBF
    • _IOLBF
    • _IONBF

5.5 打開流

#include<stdio.h>
//打開pathname指定的文件
FILE *fopen(const char *restrict pathname, const char * restrict type) ;
//在一個指定的流上打開一個指定的問文件儿礼,若流已經(jīng)打開庆寺,則先關(guān)閉該流
FILE *freopen(const char *restrict pathname, const char * restrict type,FILE * restrict fp) ;
//取一個已有的文件描述符,并使一個標(biāo)準(zhǔn)io流于該文件描述符結(jié)合(使用fd打開流)
//此函數(shù)常用于創(chuàng)建管道和網(wǎng)絡(luò)通信通道函數(shù)返回的描述符
FILE *fdopen(int fd, const char *type) ;
        //成功返回文件指針知纷,錯誤返回NULL

5.6 讀和寫流

  • 一旦打開了流陵霉,則可以使用三種類型的io進(jìn)行讀寫操作
    • 一個字符的io

    • 每次一行的io
      • 使用fgets和fputs
    • 直接io
      • fread
      • fwrite
  • 輸入函數(shù)
    • 一次讀取一個字符
      #include <stdio.h>
      //可被實現(xiàn)為宏,所以調(diào)用時間更短
      int getc(FILE *fp) ;
      //一定是一個函數(shù)踊挠,可以得到地址
      int fgetc(FILE *fp) ;
      //等于 getc(stdin)
      int getchar(void) ;
          //成功,返回下一個字符睹酌,達(dá)到尾端或出錯返回EOF    
          //這三個函數(shù)在返回下一個字符時剩檀,將其unsigned char轉(zhuǎn)換為int 
      
      • 不論是出錯還是達(dá)到結(jié)尾,這幾個函數(shù)返回值都一樣辐啄,所以需要下面的函數(shù)區(qū)分
          #include<stdio.h>
          int ferror(FILE *fp) ;
          int feof(FILE *fp) ;
      
          void cleanerr(FILE * fp) ;
      
      • 為每個流在FILE對象中維護(hù)了兩個標(biāo)志
        • 出錯標(biāo)志
        • 文件結(jié)束標(biāo)志
      • 調(diào)用cleanerr可以清楚這兩個標(biāo)志
    • 從流中讀取數(shù)據(jù)后,可以調(diào)用ungetc將字符在壓送回流中
        #include<stdio.h>
        int ungetc(int c, FILE *fp) ;
            /成功返回c失敗返回EOF
    
      -壓送回流的字符又可以從流中讀出
    
    • 壓送回的字符沒有寫入設(shè)備而是寫回標(biāo)準(zhǔn)io的緩沖區(qū)
  • 輸出函數(shù)
    • 和輸出相對應(yīng)
    #include<stdio.h>
    int putc(int c, FILE *fp) ; //可被實現(xiàn)為宏
    int fputc(int c ,FILE *fp) ;
    int putchar(int c) ;
    //成功返回c失敗返回EOF

5.7 每次1行io

  • 輸入
    #include<stdio.h>
    //從指定的流中讀,必須指定緩沖區(qū)的長度洗出,緩沖區(qū)以null字節(jié)結(jié)尾
    char *fgets(char *restrict buf, int n, FILE *restrict fp) ;
    //從標(biāo)準(zhǔn)輸入讀
    char * gets(char *buf) ;
    //  成功返回buf翩活,失敗或到達(dá)尾端返回NULL
    //這兩個函數(shù)都指定了緩沖區(qū)的地址,讀入的行將送入其中
  • 輸處
    #include<stdio.h>
    //從指定的流中讀菠镇,必須指定緩沖區(qū)的長度,緩沖區(qū)以null字節(jié)結(jié)尾
    char *fputs(char *restrict str, int n, FILE *restrict fp) ;
    //從標(biāo)準(zhǔn)輸入讀
    char * puts(const char *buf) ;
    //  成功返回非負(fù)值蚌本,失敗返回EOF
    //這兩個函數(shù)都指定了緩沖區(qū)的地址隘梨,讀入的行將送入其中

5.8 標(biāo)準(zhǔn)io的效率

  • 盡量使用按行讀取的

5.9 二進(jìn)制io

  • 當(dāng)需要讀取一個結(jié)構(gòu)或者對象的時候就不能使用按行和按字符讀取
    size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp) ;
    size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp) ;
    // 返回讀寫的對象數(shù)
  • size使對象結(jié)構(gòu)的sizeof,nobj應(yīng)該使對象的個數(shù)轴猎,如果一個5各元素的數(shù)組,我希望讀三個元素锐峭,則nobj為3

5.10 定位流

三種方法定位標(biāo)準(zhǔn)io流

  • ftell和fseek函數(shù)
  • ftello和fseeko
  • fgetpos和fsetpos

5.11 格式化io

5.12 實現(xiàn)細(xì)節(jié)

  • 每個標(biāo)準(zhǔn)io都要調(diào)用系統(tǒng)io
  • 每個標(biāo)準(zhǔn)io都有一個與其關(guān)聯(lián)的文件描述符
int fileno(FILE *fp) ;
    //返回與流相關(guān)的文件描述符
  • 如果調(diào)用dup或者fcntl可婶,則需要這個函數(shù)

5.13 臨時文件

    #include<stdio.h>
    char *tmpnam(char *ptr) ;
    FILE *tmpfile(void) ;
    //  成功返回文件指針,出錯返回NULL
  • 上面兩個文件用于創(chuàng)建臨時文件
  • tmpfile函數(shù)經(jīng)常先調(diào)用tempnam產(chǎn)生一個唯一的路徑名抛寝,然后用改路徑名創(chuàng)建一個文件曙旭,并立刻unlink它。
  • 關(guān)閉文件或程序結(jié)束時钻趋,臨時文件自動刪除

5.14 內(nèi)存流

  • 標(biāo)準(zhǔn)io庫把數(shù)據(jù)緩存在內(nèi)存中
  • 可以調(diào)用setbuf或setvbuf讓io庫緩沖數(shù)據(jù)到我們自己的緩沖區(qū)
  • 三個函數(shù)用于內(nèi)存流的創(chuàng)建
    FILE *fmemopen(void *restrict buf, size_t size, const char *restrict type) ;
    //成功返回流指針剂习,錯誤返回NULL

5.15 標(biāo)準(zhǔn)io替代軟件

第六章:系統(tǒng)數(shù)據(jù)文件信息

6.1 引言

  • 由于歷史原因较沪,系統(tǒng)一些數(shù)據(jù)文件都是ACSCII文本文件失仁,且使用標(biāo)準(zhǔn)io庫讀這些文件
  • 本章主要介紹非ascii文本格式讀取系統(tǒng)文件的接口
    6.2 口令文件
  • unix系統(tǒng)口令文件(用戶數(shù)據(jù)庫)包包含在<pwd.h>定義的passwd結(jié)構(gòu)中
  • 口令文件時/etc/passwd
  • 阻止一個用戶登陸系統(tǒng)可以使用/dev/null或者/bin/false作為登陸shell尸曼,登錄時以不成功終止
  • nobody表示任何人都可以i登陸系統(tǒng),但是用戶id和組id只能訪問人人皆可讀可寫的權(quán)限

6.3 shadow passwd(陰影文件)

  • 現(xiàn)在的unix系統(tǒng)將加密后的密碼放在另外一個文件中/etc/shadow萄焦。該文件至少包含用戶名和加密口令控轿。

6.4 組文件

unix組文件

6.5 附屬組id

在unix系統(tǒng)中,附屬組的優(yōu)點時不必顯式的更改組拂封,一個用戶參與多個項目茬射,也就屬于多個組。

6.7 其他數(shù)據(jù)文件

  • /etc/services --記錄各網(wǎng)絡(luò)服務(wù)器所提供服務(wù)的數(shù)據(jù)文件
  • /etc/protocols -- 記錄 協(xié)議信息
  • /etc/networks -- 記錄網(wǎng)絡(luò)信息
  • 不同的口令文件需要使用不同的頭文件來導(dǎo)入執(zhí)行改文件的函數(shù)
    6.8 登陸賬戶記錄
    utmp 文件記錄當(dāng)前登陸到系統(tǒng)的各個用戶
    wtmp文件跟蹤各個登陸和注銷事件

6.9 系統(tǒng)標(biāo)識

int uname(struct utsname *name) ;
  • 通過該函數(shù)的參數(shù)向其傳遞一個utsname結(jié)構(gòu)的地址冒签,然后該函數(shù)填寫此結(jié)構(gòu)在抛。

6.10 時間和日期例程

  • unix內(nèi)核提供的基本時間服務(wù)是計算自UTC時間以來經(jīng)過的秒數(shù),這個時間是日歷時間
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萧恕,一起剝皮案震驚了整個濱河市刚梭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌廊鸥,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惰说,死亡現(xiàn)場離奇詭異磨德,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吆视,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門典挑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啦吧,你說我怎么就攤上這事您觉。” “怎么了授滓?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵琳水,是天一觀的道長。 經(jīng)常有香客問我般堆,道長在孝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任淮摔,我火速辦了婚禮私沮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘和橙。我一直安慰自己仔燕,他們只是感情好造垛,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晰搀,像睡著了一般五辽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上外恕,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天奔脐,我揣著相機(jī)與錄音,去河邊找鬼吁讨。 笑死,一個胖子當(dāng)著我的面吹牛峦朗,可吹牛的內(nèi)容都是我干的建丧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼波势,長吁一口氣:“原來是場噩夢啊……” “哼翎朱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起尺铣,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤拴曲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凛忿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澈灼,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年店溢,在試婚紗的時候發(fā)現(xiàn)自己被綠了叁熔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡床牧,死狀恐怖荣回,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情戈咳,我是刑警寧澤心软,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站著蛙,受9級特大地震影響删铃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜册踩,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一泳姐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暂吉,春花似錦胖秒、人聲如沸缎患。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挤渔。三九已至,卻和暖如春风题,著一層夾襖步出監(jiān)牢的瞬間判导,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工沛硅, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留眼刃,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓摇肌,卻偏偏與公主長得像擂红,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子围小,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理昵骤,服務(wù)發(fā)現(xiàn),斷路器肯适,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時变秦,會觸發(fā)此異常。 O...
    我想起個好名字閱讀 5,256評論 0 9
  • 1. 基礎(chǔ)知識 1.1框舔、 基本概念蹦玫、 功能 馮諾伊曼體系結(jié)構(gòu)1、計算機(jī)處理的數(shù)據(jù)和指令一律用二進(jìn)制數(shù)表示2刘绣、順序執(zhí)...
    yunpiao閱讀 5,269評論 1 22
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,370評論 0 5
  • 做钳垮,還有成功的可能,不做额港,餡餅自然也砸不到你的頭上饺窿。 天上不會掉餡餅。就像有個笑話說的一樣:有個人不斷祈求上蒼讓他...
    呼蔥喚土豆閱讀 183評論 0 2