《APUE》笔记-第五章-标准I/O库

时间:2022-12-26 10:03:28
#include <stdio.h>

FILE *fopen(const char *restrict pathname, const char *type);
FILE *freopen(const char *restrict pathname, const char *type, FILE *restrict fp);//将一个指定的文件打开为一个预定义的流
FILE *fdopen(int fd, const char *type);
//成功,返回文件指针;失败,返回NULL

int fwide(FILE *fp, int mode);
//<0, 字节定向;>0,宽定向;=0,未定向

void setbuf(FILE *restrict fp, char *restrict buf);
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);//_IOFBF,_IOLBF,_IONBF
//成功,返回0;失败,返回非0

int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
//成功,返回下一个字符;失败,返回EOF

char *fgets(char *restrict buf, int n, FILE *restrict fp);
//成功,返回buf;文件尾或失败,返回NULL

int ungetc(int c, FILE *fp);//将字符c压入流fp
//成功,返回c;失败,返回EOF

int fclose(FILE *fp);
int fflush(FILE *fp);
//成功,返回0;失败,返回EOF

int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
//成功,返回c;出错,返回EOF

int fputs(const char *restrict str, FILE *restrict fp);
//成功,返回非负值;出错,返回EOF

int fread(char *restrict ptr, size_t size, size_t nobj, FILE *restrict fp); //一次读取一个完整的结构,size:每个对象的大小,nobj:对象的个数
int write(const char *restrict ptr, size_t size, size_t nobj, FILE *restrict fp); //一次写一个完整的结构,size:每个对象的大小,nobj:对象的个数
//返回读写的字节数;

long ftell(FILE *fp);//返回当前偏移量
int fseek(FILE *fp, long offset, int whence);//设置偏移量

void rewind(FILE *fp);//将一个流设置到文件的起始位置


格式化I/O

int printf(const char *restrict format,  ...);
int fprintf(FILE *restrict fp,  const char *restrict format,  ...);
int dprintf(int fd,  const char *restrict format,  ...);
                                                       成功:返回输出字符数;失败,返回负值
int sprintf(char *restrict buf,  const char *restrict format,  ...);
int snprintf(char *restrict buf,  size_t n, const char *restrict format,  ...); //解决sprintf的缓冲区会溢出的问题

成功:返回存入数组的字符数;出错,返回负值


int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);


//每个标准的I/O流都有一个与其相关联的文件描述符

int fileno(FILE *fp); //获得fp的fd


写个程序,练习一下:

#include <stdio.h>
#include <wchar.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFSIZE 100

int main()
{
FILE *pfile = NULL;
FILE *pfile2 = NULL;

int fd, n;
char buf[BUFSIZE];

//输出文件file内容到屏幕
fd = open("file", O_RDONLY);
if (fd == -1)
{
printf("open() error\n");
exit(-1);
}
n = read(fd, buf, BUFSIZE);
if (n == -1)
{
printf("read() error\n");
exit(-1);
}
if (write(STDOUT_FILENO, buf, n) != n)
{
printf("write() error\n");
exit(-1);
}

pfile = fopen("file", "r+");
if (pfile == NULL)
exit(-1);
printf("fopen() ok\n");

pfile2 = freopen("newfile", "w", stderr);//将"newfile"设置为标准输出
if (pfile2 == NULL)
exit(-1);
printf("freopen() ok\n");

pfile2 = fdopen(open("newfile", O_RDONLY), "r");
if (pfile2 == NULL)
exit(-1);
printf("fdopen() ok\n");

int status;
status = fwide(pfile, -1);//将流pfile设置为字节定向
if (status >= 0)
exit(-1);
printf("fwide() ok\n");

setbuf(pfile2, NULL);//关闭缓冲
printf("setbuf() ok\n");

status = setvbuf(pfile, buf, _IOFBF, BUFSIZE);
if (status != 0)
exit(-1);
printf("setvbuf() ok\n");

int c = getc(pfile);
if (c == EOF)
exit(-1);
printf("getc() ok, letter from pfile is: %c\n", c);

c = fgetc(pfile);
if (c == EOF)
exit(-1);
printf("fgetc() ok, letter from pfile is: %c\n", c);

printf("enter a letter: ");
c = getchar();//从标准输入读
if (c == EOF)
exit(-1);
printf("getchar() ok, your input is: %c\n", c);

if (ungetc(c, pfile) == EOF)//字母c压入流缓冲区
exit(-1);
printf("ungetc() ok\n");

if (fgets(buf, BUFSIZE, pfile) == NULL)//fgets遇到换行符终止
exit(-1);
printf("fgets() ok, now, buf is: %s\n", buf);

c = 'b';
if (putc(c, pfile) == EOF)
exit(-1);
printf("putc() ok\n");

if (fputc(c, pfile) == EOF)
exit(-1);
printf("fputc() ok\n");

if (putchar(c) == EOF)//输出到屏幕
exit(-1);
printf("\nputchar() ok\n");

if (fputs(buf, pfile) == EOF)
exit(-1);
printf("fputs() ok\n");

fseek(pfile, 0, SEEK_SET);//偏移量设置到文件起始位置
printf("fseek() ok, now offset is: %d\n", ftell(pfile));
if (fread(buf, 1, 5, pfile) != 5)//一次读取5个1字节
exit(-1);
printf("fread() ok\n");

if (fwrite(buf, 1, 5, stdout) != 5)//一次写5个1字节
exit(-1);
printf("\nfwrite() ok\n");

printf("ftell() ok, now offset is: %d\n", ftell(pfile));
rewind(pfile);//将一个流设置到文件的起始位置
printf("rewind() ok, now offset is: %d\n", ftell(pfile));

printf("fileno() ok, fd of pfile is : %d\n", fileno(pfile));//获取流的文件描述符

fseek(pfile, 0, SEEK_END);
fprintf(pfile, "something come from fprintf()\n");//标准输出到流pfile

fclose(pfile);
fclose(pfile2);

return 0;
}

结果如下:

《APUE》笔记-第五章-标准I/O库

第2次运行程序,结果如下:
《APUE》笔记-第五章-标准I/O库

分析:

1.调用open、read、write输出文件file内容

2.调用fopen流pfile,打开后流pfile和文件file绑定在一起,因为后面要写入流,所以用"r+"

3.调用freopen,将流文件newfile设置为标准错误

4.在文件描述符上打开一个流

5.-1,小于0,设置为字节定向

6.setbuf的参数为NULL,代表关闭缓冲;否则是全缓冲或行缓冲

7.pfile设置为全缓冲,_IOFBF、_IOLBF、_IONBF

8.getc读取一个字符,宏;fgetc读取一个字符,函数;getchar从标准输入读

9.用ungetc压入字符到流的缓冲区中,并未写到底层文件中。

10.fgets一次读取一行,遇到换行符终止;不用gets,因为不能手动设置缓冲区大小,可能会造成缓冲区溢出

11.putc输出一个字符,宏;fputc输出一个字符,函数;fputc输出到标准输出

12.fputs一次输出一行;不用puts,因为不能手动设置缓冲区大小,可能会造成缓冲区溢出

13.ftell返回偏移量,fseek设置偏移量,rewind设置流偏移量到文件起始位置 SEEK_CUR SEEK_SET SEEK_END

14.fread、fwrite用于二进制文件,一次读写指定大小指定数量的对象

15.fprintf标准输出到流

16.关闭流,文件被关闭前,冲洗缓冲区输出数据,丢弃缓冲区输入数据