APUE读书笔记(三)

5 标准I/O库

流和FILE对象

流的定向决定了读写字符是单字节(字节定向)还是多字节(宽定向)。
设置流的定向的模式(不改变已定向流):

#include <stdio.h>
#include <wchar.h>
int fwide(FILE *fp, int mode);
//返回值:流为宽定向则返回正值,字节定向则返回负值,未定向则返回0
/*
mode为负则指定字节定向;
mode为正则指定宽定向;
mode为0则不作设置而返回当前流定向状态
*/

标准输入、标准输出和标准错误

标准输入、标准输出和标准错误的FILE流指针分别为stdinstdoutstderr

缓冲

标准I/O提供:

  1. 全缓冲;
  2. 行缓冲;
  3. 不带缓冲。

冲洗是缓冲区的写操作。
不指向交互式设备的标准输入和标准输出是全缓冲(反之是行缓冲),标准错误不带缓冲。
更改缓冲类型:

#include <stdio.h>
void setbuf(FILE *restrict fp, char *restrict buf);//buf为NULL则不带缓冲(否则缓冲区长度为BUFSIZE)
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);//mode为_IOFBF或_IOLBF且buf为NULL则选择合适长度系统缓冲区,为_IONBF且buf为NULL则无缓冲
//返回值:成功则返回0,出错则返回非0
/*
mode:
_IOFBF为全缓冲;
_IOLBF为行缓冲;
_IONBF为不带缓冲
*/

强制冲洗一个流(使所有未写的数据被传送至内核):

#include <stdio.h>
int fflush(FILE *fp);
//返回值:成功则返回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);//将打开流指定为fp(已定向则先清除)
FILE *fdopen(int fd, const char *type);
//返回值:成功则返回文件指针,出错则返回NULL
/*
type:
"r"或"rb"即读打开;
"w"或"wb"即把文件截断至0或写打开;
"a"或"ab"即追加(在文件尾写打开或写创建);
"r+"或"r+b"或"rb+"即读写打开;
"w+"或"w+b"或"wb+"即把文件截断至0或读写打开;
"a+"或"a+b"或"ab+"即在文件尾读写打开或读写创建
*/

关闭打开的流(关闭前冲洗缓冲区):

#include <stdio.h>
int fclose(FILE *fp);
//返回值:成功则返回0,出错则返回EOF

进程正常终止时会关闭所有打开的标准I/O流(先会冲洗缓冲区)。

读和写流

打开流后3种非格式化I/O:

  1. 每次一字符的I/O;
  2. 每次一行的I/O;
  3. 直接I/O。

一次读一字符:

#include <stdio.h>
int getc(FILE *fp);//可被实现为宏
int fgetc(FILE *fp);
int getchar(void);//等同于getc(stdin)
//返回值:若成功则返回下一字符,若已到达文件尾或出错则返回EOF

流的出错相关操作:

#include <stdio.h>
int ferror(FILE *fp);//检测出错
int feof(FILE *fp);//检测文件结束
//返回值:条件为真则返回非0,否则返回0

void clearerr(FILE *fp);//清除出错和文件结束标志

将字符压到流中:

#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);//等同于putc(c, stdout)
//返回值:成功则返回c,出错则返回EOF

每次一行I/O

每次读一行:

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);//读到下一个换行符为止(读进去),不超过n-1个字符,缓冲区以null字节结尾
char *gets(char *buf);//与stdin相连,避免使用(不安全,缓冲区可能溢出)
//返回值:成功则返回buf,已达到文件尾或出错则返回NULL

每次写一行:

#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);//以null字节分割字符串但不将其写出(与换行符无关)
int puts(const char *str);//与stdout相连,不推荐使用(不是不安全,尾部会加个换行符)
//返回值:成功则非负值,出错则返回EOF

标准I/O效率

标准I/O库与直接调用readwrite相比不慢很多。

二进制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);
//返回值:读或写的对象数

二进制I/O可移植性较差。

定位流

三种方法定位标准I/O流:

  1. 假定文件的位置可以存放在长整型中:
#include <stdio.h>
long ftell(FILE *fp);//得到当前位置
//返回值:成功则返回当前文件位置指示,出错则返回-1L

int fseek(FILE *fp, long offset, int whence);//设置位置
//返回值:成功则返回0,出错则返回-1

void rewind(FILE *fp);//回绕
  1. 使用off_t
#include <stdio.h>
off_t ftello(FILE *fp);//得到当前位置
//返回值:成功则返回当前文件位置,出错则返回(off_t)-1

int fseeko(FILE *fp, off_t offset, int whence);//设置位置
//返回值:成功则返回0,出错则返回-1
  1. 由ISO C引入(可移植性好):
#include <stdio.h>
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);//得到当前位置
int fsetpos(FILE *fp, const fpos_t *pos);//设置位置
//返回值:成功则返回0,出错则返回

格式化I/O

  1. 格式化写:
#include <stdio.h>
int printf(const char *restrict format, ...);//与stdout相连
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, ...);
//返回值:缓冲区足够大则返回将要存入数组的字符数,编码出错则返回负值

使用arg的版本:

#include <stdarg.h>
#include <stdio.h>
int vprintf(const char *restrict format, va_list arg);//与stdout相连
int vfprintf(FILE *restrict fp, const char *restrict format, va_list arg);
int vdprintf(int fd, const char *restrict format, va_list arg);
//返回值:成功则返回输出字符数,输出错误则返回负值

int vsprintf(char *restrict buf, const char *restrict format, va_list arg);//不安全(缓冲区可能溢出)
//返回值:成功则返回存入数组的字符数,编码出错则返回负值

int vsnprintf(char *restrict buf, size_t n, const char *restrict format, va_list arg);
//返回值:缓冲区足够大则返回将要存入数组的字符数,编码出错则返回负值
  1. 格式化读:
#include <stdio.h>
int scanf(const char *restrict format, ...);//与stdin相连
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);
//返回值:赋值的输入项数,输入出错或任一转换前已到达文件尾则返回EOF

使用arg的版本:

#include <stdarg.h>
#include <stdio.h>
int vscanf(const char *restrict format, va_list arg);//与stdin相连
int vfscanf(FILE *restrict fp, const char *restrict format, va_list arg);
int vsscanf(const char *restrict buf, const char *restrict format, va_list arg);
//返回值:指定的输入项数,输入出错或任一转换前已到达文件尾则返回EOF

函数fileno

将流指针转换为文件描述符:

#include <stdio.h>
int fileno(FILE *fp);
//返回值:与该流相关联的文件描述符

临时文件

ISO C提供的关于临时文件的函数:

#include <stdio.h>
char *tmpnam(char *ptr);//仅生成文件名并存放在ptr中,ptr为NULL则其存在静态区(会复用)中
//返回值:指向唯一路径名的指针

FILE *tmpfile(void);//生成文件名并创建它,其为二进制文件(wb+),关闭文件或程序结束时自动删除(先unlink)
//返回值:成功则返回文件指针,出错则返回NULL

SUS也定义了关于临时文件的函数:

#include <stdlib.h>
char *mkdtemp(char *template);//创建目录(有用户读写执行权限,不自动删除)
//返回值:成功则返回指向目录名的指针,出错则返回NULL

int mkstemp(char *template);//创建文件(不自动删除)
//返回值:成功则返回文件描述符,出错则返回-1

内存流

创建内存流:

#include <stdio.h>
FILE *fmemopen(void *restrict buf, size_t size, const char *restrict type);//流关闭时缓冲区释放,会自动添加null字节
//返回值:成功则返回流指针,错误则返回NULL

其他创建内存流的两个函数:

#include <stdio.h>
FILE *open_memstream(char **bufp, size_t *sizep);
#include <wchar.h>
FILE *open_wmemstream(wchar_t **bufp, size_t *sizep);
//返回值:成功则返回流指针,出错则返回NULL
//只能写打开,无法指定自己的缓冲区(但可以访问其地址和大小),流关闭时缓冲区释放,可以对缓冲区扩容
posted @ 2020-10-05 23:02  SIGMA711  阅读(130)  评论(0编辑  收藏  举报