# I/O操作 输入输出是一切实现的基础。 标准IO:`stdio` 系统调用IO(文件IO):`sysio` 优先使用标准IO,兼容性更好,还有合并系统调用的优势。 ```c /* stdio */ /* FILE类型贯穿始终 */ FILE *fopen(const char *path, const char *mode); /** * fopen 返回指针的储存位置? 1.栈 2.静态区 3.堆 * 正确答案:3.堆。 * 因为如果是栈,就是函数内部局部变量,无法返回地址。 * 如果是静态区,无法确定需要多少个这个变量。 * * 只有 r 和 r+ 一定要求文件存在 * 另外几种不存在会创建 * * 创建文件的权限 * 0666 & ~umask * * 对于普通用户 * umask 得到 022 * */ int fclose(FILE *fp); int fputc(FILE *stream); int fgetc(int c, FILE *stream); char *fgets(char *s, int size, FILE *stream); /** * 两种正常返回的情况: * 1. 读了 size-1 个字节,最后一个字节留给 '\0' * 2. 读到了 '\n' * * eg. 加入用fgets(buf, 5, stream) 来读 abcd * 是会读两次的 * 第一次:abcd'\0' * 第二次:'\n''\0' */ int fputs(const char *restrict s, FILE *restrict stream); /** * 这一对函数常用但是无法验证边界 * 尽量一次只读单字节,更安全 * * 返回值:成功读/写的对象的数量 */ size_t fread(void *ptr, size_t size, size_t nemmb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); int printf(const char *restrict format, ...); /** * 常用于 fprintf(stderr,...) */ int fprintf(FILE *restrict stream, const char *restrict format, ...); // TODO: int dprintf(int fd, const char *restrict format, ...); /** * 将格式化内容输出到一个字符串 * * 和 atoi() 正好相反 * */ int sprintf(char *restrict str, const char *restrict format, ...); /** * 比sprintf多了size参数,更安全 */ int snprintf(char str[restrict.size], size_t size, const char *restrict format, ...) // !!! 慎用%s int scanf(const char *restrict format, ...); int fscanf(FILE *restrict stream, const char *restrict format, ...); /** * 移动文件当前位置指针 * * 可用于生成空洞文件,下载器原理 * * @prarm: offset 移动多远 * @prarm: whence 移动方向 * SEEK_SET, SEEK_CUR, SEEK_END * * @return 成功0,失败-1 */ int fseek(FILE *stream, long offset, int whence); /** * 反映当前文件指针所在位置 * * 这个long的负值部分无法使用。 * 所以文件无法超过2G。 * */ long ftell(FILE *stream); /** * 解决上面long的问题。 * * 最好编译时加上 * #define _FILE_OFFSET_BITS 64 * 可以写入makefile * * 但是这俩函数是方言,前面那个long的一对支持C89,C99 * */ int fseeko(FILE *stream, off_t offset, int whence); off_t ftello(FILE *stream); /** * 将文件指针置于文件首 * equivalent to: * fseek(stream, 0L, SEEK_SET); */ void rewind(FILE *stream); /** * 缓冲区的作用: * 大多数情况下是好事,合并系统调用 * * 行缓冲: 换行时候刷新,满了的时候刷新,强制刷新(标准输出是这样的,因为是终端设备) * * 全缓冲: 满了的时候刷新,强制刷新(默认,只要不是终端设备) * * 无缓冲: 如stderr,需要立即输出的内容 */ fflush(); /** * @prarm: mode * _IONBF * _IOLBF * _IOFBF */ int setvbuf(FIEL *stream, char *buf, int mode, size_t size); ``` P131