chapter 5 標準I/O庫

     標準I/O庫主要是由ANSI C實現的。主要是爲了在不同操作系統上實現。

     在UNIX中,標準I/O庫的最終都要調用I/O例程。

     標準I/O庫的操作都是圍繞stream來進行的。與流相對應的是FILE對象的指針,這個FILE對象的指針和file描述符是有差別的,這是一個結構體,定義在stdio.h中,不同於file描述符就是一個int型數據。

     預定義的stream是有三個:stdin,stdout,stderr。對應的文件描述符分別是:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO。

     緩存分三種:_IOFBF,_IOLBF,_IONBF,全緩存,行緩存,沒有緩存。默認的,stdin和stdout是行緩存,stderr是不帶緩存。緩存類型是可以設置的:

     #include <stdio.h>

     void setbuf(FILE* fp, char* buf);

     void setvbuf(FILE* fp, char* buf, int mode, size_t size);

     其中,setbuf有buf來決定是否帶緩存,而setvbuf是通過mode來決定是哪一種緩存,而buf來決定是用戶緩存還是系統緩存,如果是系統緩存,則size是沒有意義的。系統緩存的size是由系統決定的,可能是st_blksize,也可能是BUFSIZE。這個由系統來決定。

     流可以直接刷新,可以強制刷出:

     #include <stdio.h>

     int  fflush(FILE* fp);

     一個通用的過程應該是:打開---->讀寫----->關閉,其他還有 定位, 格式化I/O, 臨時文件。

     打開:

     #include <stdio.h>

     FILE* fopen(const char* pathname, const char* type);

     FILE* freopen(const char* pathname, const char* type, FILE* fp);

     FILE* fdopen(int filedes, const char* type);

其中,freopen 在一個特定的流上打開一個指定的文件。此函數一般用於將一個指定的文件打開爲一個預定以的流:stdin,stdout,stderr。

fdopen則是把filedes轉爲FILE*。

type是規定讀寫方式:r w a +

b在unix內核中不起作用,因爲內核不區分文本文件和2進制文件。

    對應的關閉:

    int fclose(FILE* fp);

    正常終止進程,流會被flush,並關閉。


    讀寫分爲三種:

1,字符讀寫:

#include <stdio.h>

int getc(FILE* fp);

int fgetc(FILE* fp);

int getchar(void);


int putc(int c, FILE* fp);

int fputc(int c, FILE* fp);

int putchar(int c);

其中,getchar是getc的特殊形式,fp是stdin。putchar是putc的特殊形式,fp是stdout.

getc和putc可以用宏實現,所以會快一些。而fgetc和fputc可以作爲函數參數。

getc和fgetc是返回值在出錯和文件結尾的時候都返回EOF,可以用如下函數判斷:

int ferror(FILE* fp);

int feof(FILE* fp);

清除標誌用:

int clearerr(FILE* fp);

獲取字符可以回送,取出來看一下,然後送回去,想用的話在get:

int ungetc(int c, FILE* fp);

EOF不能回送。


2 行讀寫:

#include <stdio.h>

char* fgets(char* buf, int n, FILE* fp);

char* gets(char* buf);


char* fputs(const char* str, FILE* fp);

char* puts(const char* str);

其中,gets可能會出現緩存越界。fgets讀取n-1個字符。

fputs將一個以null符終止的字符串寫到指定的流,null 不寫出。


3 二進制讀寫:

這個主要是讀取一個結構體(包括數組)之類的完整數據。

#include <stdio.h>

size_t fread(void* ptr, size_t size, size_t nobj, FILE* fp);

size_t fwrite(const void* ptr, size_t size, size_t nobj, FILE* fp);

跨系統很難工作。


打開-->讀寫-->關閉,然後就是定位

1 unix系統老的方法:

#include <stdio.h>

long ftell(FILE* fp);

int fseek(FILE* fp, long offset, int whence);

void rewind(FILE* fp);

其中,rewind定位到0;

whence可以是: SEEK_SET,SEEK_CUR,SEEK_END.

事實上,文本文件不能單純的用long值來表示。


2 ANSI C引入的:

#include <stdio.h>

int fgetpos(FILE* fp, fpos_t* pos);

int fsetpos(FILE* fp, const fpos_t* pos);


格式化I/O:

#include <stdio.h>

int printf(const char* format, ......);

int fprintf(FILE* fp, const char* format, ......);

int sprintf(char* buf, const char* format, ......);


int scanf(const char* format, ......);

int fscanf(FILE* fp, const char* format, ......);

int sscanf(const char* buf, const char* format, ......);

其中,sprintf可能會越界,必須有調用者來控制。

輸出有一個變種如下:

#include <stdio.h>

#include <stdarg.h>

int vprintf(const char* format, va_list arg);

int vfprintf(FILE* fp, const char* format, va_list arg);

int vsprintf(char* buf, const char* format, va_list arg);


之前有將filedes轉爲FILE*的,

     FILE* fdopen(int filedes, const char* type);

反之:

     int fileno(FILE* fp);


臨時文件

#include <stdio.h>

char* tmpnam(char* ptr);

FILE* tmpfile(void);

其中,tmpnam中ptr和返回值是一致的。ptr如果是null,再次調用該函數時是會重寫原先的文件名的,所以如果想保存是不能僅保存指針的。

變種:

char* tempnam(const char* directory, const char* prefix);

臨時文件的目錄有一個順序,最好就直接用這個函數規定就好了。

TMPDIR>directory>P_tmpdir>/tmp


本章基本就是這些內容了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章