APUE(5)---標準I/O庫 (2)

6、讀和寫流數組

  一旦打開了流,則可在3種不一樣類型的非格式化I/O中進行選擇,對其進行讀、寫操做:1)每次一個字符的I/O,一次讀或寫一個字符,若是劉時代緩衝的,則標準I/O函數處理全部緩衝;2)每次一行的I/O。若是想要一次讀或寫一行,則使用fgets和fputs。每行都以一個換行符終止。當調用fgets時,應說明能處理的最大行長。3)直接I/O(這個術語來自ISO C標準,有時也被稱爲二進制I/O,一次一個對象的I/O、面向記錄的I/O或面向結構的I/O)。fread和fwrite函數支持這種類型的I/O。每次I/O操做讀或寫某種數據的對象,而每一個對象具備指定的長度。這兩個函數經常使用於從二進制文件每次讀或寫一個結構。安全

1.輸入函數函數

#include <stdio.h>
int get(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
//若成功,返回下一個字符;若已經到達文件尾端或出錯,返回EOF

  函數getchar等同於fgetc(stdin)。前兩個函數的區別是getc可被實現爲宏,而fgetc不能被事先未宏,這意味着如下幾點區別:1)getc的參數不該當是具備反作用的表達式,由於他可能會被計算屢次;2)由於fgetc必定是個函數,因此能夠獲得其地址。這就容許將fgetc的地址做爲一個參數傳送給另外一個函數;3)調用fgetc所需時間極可能比調用getc要長,由於調用函數所需的時間一般長於調用宏。spa

  須要注意的是不論是出錯仍是達到文件的尾端,這三個函數都返回一樣的值,爲了區分這兩種不一樣的狀況,必須調用ferror或feof,這是由於大多數實現中,爲每一個流在FILE對象中維護了兩個標誌:出錯標誌;文件結束標誌。clearerr能夠清除這兩個標誌。rest

#include <stdio.h>
int gerror(FILE *fp);
int feof(FILE *fp);
//若條件爲真,返回非0;不然,返回0

void clearerr(FILE *fp);

  從流中讀取數據之後,能夠調用ungetc將字符再壓送回流中。壓送回流中的字符之後又可從流中讀出,但讀出字符的順序與壓送回的順序相反。不能回送EOF,。可是當已經到達文件尾端時,仍能夠回送一個字符。下次讀將返回該自負,再讀則返回EOF。之因此能這樣作的緣由是:一次成功的ungetc調用會清除該流的文件結束標誌。用ungetc壓送回字符時,並無將他們寫到底層文件中或設備上,知識將它們寫會標準I/O庫的流緩衝區中。code

#include <stdio.h>
int ungetc(int c, FILE *fp);
//若成功,返回c;若出錯,返回EOF

二、輸出函數
  對應於上面所述的每一個輸入函數都有一個輸出函數:對象

#include <stdio.h>
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);

7、每次一行I/Oblog

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *restrict buf);

  對於fgets,必須指定緩衝的長度n,次函數一直讀到下一個換行符爲止,可是不超過n-1個字符,讀入的字符被送入緩衝去。該緩衝區以null字節結尾。如該行包括最後一個換行符的字符數超過n-1,則只返回一個不完整的行,可是,緩衝區老是yinull字節結尾。對fgets的下一次調用會繼續該執行。gets不推薦使用,可能形成緩衝區溢出。ci

#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
//若成功,返回非負值;若出錯,返回EOF

  fputs講一個以null字節終止的字符串寫到指定的流,尾端的終止符null不寫出。puts並不像它所對應的gets那樣不安全,可是咱們仍是應避免使用它,以避免須要記住它最後是否添加一個換行符。字符串

8、標準I/O的效率

#include <apue.h>
#include <my_err.h>

int main(void)
{
    int c;
    while((c = getc(stdin)) != EOF)
    {
        if(putc(c, stdout) == EOF)
        {
            err_sys("output error!");
        }
    }

    if(ferror(stdin))
    {
        err_sys("input error!");
    }

    exit(0);
}

5-4 用getc和putc將標準輸入複製到標準輸出

#include <apue.h>
#include <my_err.h>

int main(void)
{
    char buf[MAXLINE];
    while(fgets(buf, MAXLINE, stdin) != NULL)
    {
        if(fputs(buf, stdout) == EOF)
        {
            err_sys("output error!");
        }
    }

    if(ferror(stdin))
    {
        err_sys("input error!");
    }

    exit(0);
}

5-5 用fgets和fputs將標準輸入複製到標準輸出

  

函數

用戶cpu

系統cpu

時鐘時間

程序正文字節數

圖3-6最佳時間

0.05

0.29

3.18

 

fgets/fputs

2.27

0.30

3.49

143

getc/putc

8.45

0.29

10.33

114

fgetc/fputc

8.16

0.40

10.18

114

圖3-6單字節時間

134.61

249.94

394.95

 

5-6 使用標準I/O例程獲得的時間結果

一、系統CPU時間幾乎相同,緣由是由於全部這些程序對內核提出的讀寫請求數基本相同

二、fgets優於fgetc,是由於fgets底層拷貝使用memccpy,而且減小了函數調用次數

三、fgetc和getc沒有明顯區別的緣由是getc是宏簡單地擴充爲函數調用

四、fgetc、fputc大大優於單字節時間是由於雖然函數調用次數差很少,可是fgetc/fputc是普通的函數調用,而單字節是系統調用read。系統調用花費的時間大大超過普通函數調用。

9、二進制I/O

  當咱們一次須要處理一個完整的結構,咱們就須要二進制I/O。典型的應用場景如讀寫一個二進制數組;讀或寫一個結構。

#include <stdio.h>
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);
//兩個函數的返回值:讀或寫的對象數

  fread和fwrite返回讀或寫的對象數。對於讀、若是出錯或到達文件尾端,則此數字能夠少於nobj、在這種狀況,應調用ferror或feof以判斷到底是哪種狀況。對於寫,若是返回值少於所要求的nobj,則出錯。使用二進制I/O還須要注意兩個問題:1)在一個結構中,贊成成員的偏移量可能隨編譯程序和系統的不一樣而不一樣;2)用來儲存多字節整數和覆電紙的二進制格式在不一樣的系統結構間也可能不一樣。

相關文章
相關標籤/搜索