APUE: Standard I/O Library

流和FIFE對象

標準I/O文件流能夠處理單字節和寬字節. 函數fwide用於設置流的方向:數組

#include <stdio.h>ide

#include <wchar.h>函數

int fwide(FILE *fp, int mode);spa

            returns: 寬字節流則返回正數, 單字節流則返回負數, 沒有則返回0.指針

若是mode爲負數, 則函數嘗試將流設置爲單字節.rest

若是mode爲正數, 則函數嘗試將流設置爲寬字節.code

若是mode爲0, 則保持原樣.對象

當咱們使用fopen打開一個流時, 它將返回一個指針指向FILE對象. 此對象包含了流的所有信息: 文件描述符, 指針指向一個存儲流的Buffer, Buffer的大小, 已讀取流的大小, 錯誤標誌等等.ci

緩衝(Buffering)

標準I/O提供三種類型的緩衝:字符串

1. 全緩衝: 在填滿標準I/O緩衝區後才進行實際I/O操做.

2. 行緩衝: 輸入和輸出遇到換行符時候, 標準I/O執行I/O操做.

3. 不帶緩衝.

一般, 系統默認是:

1. 標準錯誤是不帶緩衝的.

2. 如如果涉及終端設備的其餘流,則它們是行緩衝的;不然是全緩衝的。

經過函數setbuf來改變流的模式:

#include <stdio.h>

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

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

                        returns: 成功返回0, 失敗返回非0.

這些函數必須在流被打開,後而且對流操做以前調用.

使用setbuf函數, 咱們能夠打開或關閉緩衝. 打開緩衝, 則buf的長度必須爲BUFSIZ, 默認狀況下爲全緩衝, 但若是流關聯到終端則會被修改成行緩衝. 若是關閉緩衝, 則buf設置爲NULL.

使用setvbuf函數, 咱們能夠顯式設置緩衝類型:

_IOFBF: 全緩衝

_IOLBF: 行緩衝

_IONBF: 非緩衝

任何狀況下, 咱們可使用如下函數強制刷新緩衝:

#include <stdio.h>

int fflush(FILE *fp);

            returns: 成功返回0, 失敗返回EOF

打開一個流

如下函數打開一個標準的I/O流:

#include <stdio.h>

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

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

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

                    returns: 成功返回文件指針, 失敗返回NULL

而type有如下類型:

type 含義
r, rb
w, wb 文件截斷爲0或者打開文件用於寫
a, ab 打開文件追加至末尾, 或者建立文件用於寫
r+, r+b, rb+ 讀寫
w+, w+b, wb+ 文件截斷爲0或建立文件用於讀寫
a+, a+b, ab+ 打開文件用於讀, 或者在文件末尾寫入

b用於代表是二進制文件仍是文本文件, 可是對於Unix來講二進制文件和文本文件並沒有區別, 因此b參數無任何影響.

使用fclose關閉一個打開流:

#include <stdio.h>

int fclose(FILE *fp);

讀取或寫入流

如下函數容許咱們一次讀取一個字符:

#include <stdio.h>

int getc(FILE *fp);

int fgetc(FILE *fp);

int getchar(void);

        returns: 成功返回下一個字符, 失敗或讀取完畢返回EOF

getchar函數等價於getc(stdin). 而getc和fgetc不一樣之處在於: getc爲宏定義, 而fgetc爲函數.

用於不管出錯仍是讀取完畢, 均返回EOF, 因此如下兩個函數用於辨別它們:

#include <stdio.h>

int ferror(FILE *fp);

int feof(FILE *fp);

            returns: 成功返回非0, 失敗返回0

錯誤標誌和EOF標誌均會綁定到FILE對象上, 使用clearerr來清除:

void clearerr(FILE *fp);

在讀取一個流以後, 咱們可使用ungetc將字符push back.

#include <stdio.h>

int ungetc(int c, FILE *fp);

        returns: 成功返回c, 失敗返回EOF

如下函數容許咱們一次寫入一個字符:

#include <stdio.h>

int putc(int c, FILE *fp);

int fputc(int c, FILE *fp);

int putchar(int c);

                returns: 成功返回c, 失敗返回EOF

一個實際的例子:

#include <stdio.h>

int main(void)
{
    unsigned int c;
    while ((c = getc(stdin)) != EOF) {
        putc(c, stdout);
    }
    return 0;
}

咱們可使用如下函數讀取和寫入一行數據:

#include <stdio.h>

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

char *gets(char *buf);

            returns: 成功返回buf, 失敗或到文件末尾返回NULL.

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

int puts(const char *str);

            returns: 成功返回非負值, 失敗返回EOF

fgets用於讀取一行, 但buf長度不可大於n.

gets函數不推薦使用, 由於沒肯定所讀取數據的長度, 容易致使溢出或者數據丟失.

而puts也不推薦使用, 由於它寫入的字符串不帶null.

一個實際的例子:

#include <stdio.h>

#define BUFFSIZE 4096
int main(void)
{
    unsigned int arr[BUFFSIZE];
    while (fgets(arr, BUFFSIZE - 1, stdin) != NULL) {
        fputs(arr, stdout);
    }
    return 0;
}

二進制I/O

在讀取二進制文件時候咱們沒法使用getc/putc, 也沒法使用fputs/fgets, 應該使用fread/fwrite:

#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);

                returns: 讀取或寫入的個數

1--讀寫一個二進制數組。例如,爲了將一個浮點數組的第2~5個元素寫至一個文件上,則代碼以下:

float data[ 10 ];
if (fwrite(&data[2], sizeof(float), 4, fp ) != 4 )
    printf("write error\n");


2--讀寫一個結構,則代碼以下:

struct {
    short count;
    long total;
    char name[ NAMESIZE ];
} item;
if ( fwrite(&item, sizeof(item), 1, fp ) != 1  )
    printf("write error\n");


    如下程序將結構寫入文件中,而後複製文件再讀取出來:

#include <stdio.h>

struct people{
	char	*name;
	int	age;
};
int main(void)
{
	int	c;
	char	buf[ 10 ];
	FILE *fp1 = fopen("people", "w+");
	FILE *fp2 = fopen("people.foo","w+");
	if (NULL == fp1 || NULL == fp2) {
		printf("open file error\n");
		return 1;
	}
	struct people p1;
	struct people p2;
	struct people p3;
	struct people p4;
	p1.name = "小雷";
	p1.age = 25;
	p2.name = "小貓咪";
	p2.age = 24;

	if (fwrite(&p1, sizeof(p1), 1, fp1) != 1) {
		printf("write error\n");
		return 1;
	}
	if (fwrite(&p2, sizeof(p2), 1, fp1) != 1) {
		printf("write error\n");
		return 1;
	}
	
	if (fseek(fp1, 0, SEEK_SET) != 0) {
		printf("fseek error\n");
		return 1;
	}	
	while ((c = getc(fp1)) != EOF) {
		if (putc(c, fp2) == EOF) {
			printf("write error\n");
			return 1;
		}
	}

	if (fseek(fp2, 0, SEEK_SET) != 0) {
		printf("fseek error\n");
		return 1;
	}
	if (fread(&p3, sizeof(p3), 1, fp2) != 1) {
		printf("read error\n");
		return 1;
	}
	if (fread(&p4, sizeof(p4), 1, fp2) != 1) {
		printf("read error\n");
		return 1;
	}
	printf("name is:%s, age is:%d\n", p3.name, p3.age);
	printf("name is:%s, age is:%d\n", p4.name, p4.age);

	return 0;
}

程序輸出:

leicj@leicj:~/test$ ./a.out
name is:小雷, age is:25
name is:小貓咪, age is:24

臨時文件

#include <stdio.h>

#define MAXLINE 4096
int main(void)
{
    char    name[L_tmpnam], line[MAXLINE];
    FILE    *fp;
    printf("%s\n", tmpnam(NULL));
    tmpnam(name);
    printf("%s\n", name);

    if ((fp = tmpfile()) == NULL) {
        printf("tmpfile error\n");
        return 1;
    }
    fputs("one line of output\n", fp);
    rewind(fp);
    if (fgets(line,sizeof(line), fp) == NULL) {
        printf("fgets error\n");
        return 1;
    }
    fputs(line, stdout);

    return 0;
}

程序輸出:

leicj@leicj:~/test$ ./a.out
/tmp/fileUmW8wA
/tmp/fileBpa2Jr
one line of output
相關文章
相關標籤/搜索