1、标准IO和系统IO的区别
| 类型 | 可移植性 | 实时性 | 吞吐量 | 功能 |
|---|---|---|---|---|
| STDIO | 高 | 低 | 高 | 受限 |
| SYSIO | 低 | 高 | 低 | 自由 |
之前学过的系统IO是由内核直接提供的函数库实现的,不同的操作系统平台上提供的IO操作接口不同。系统IO操作都是围绕文件描述符展开的,而对于标准IO是围绕流(stream)进行的。当用标准IO库打开或创建一个文件时,就使得一个流与一个文件相关联。
其次标准IO能够使用用户自定义的缓冲区,具体可以分为行缓冲、全缓冲、无缓冲。由于标准IO操作缓冲区的灵活性,使得它相比于系统IO吞吐量更高,但系统IO实时性更好。
标准IO对于驻留在磁盘上的文件通常是全缓冲,当流涉及终端时采取行缓冲。全缓冲只有缓冲区满了之后才会刷新到内核中,行缓冲在遇到换行符时就能会刷新到内核。缓冲区中的数据也可以通过fflush主动刷新到内核中。
#include <stdio.h>
int fflush(FILE *stream);
标准IO能够和系统IO相互转换:
//文件描述符转化为具体的流指针
FILE *fdopen(int fd, const char *type);
//流指针转化为文件描述符
int fileno(FILE *stream);
2、标准IO进行读写
2.1 fopen
//打开指定路径的文件,返回文件流指针
FILE *fopen(const char *path, const char *mode);
参数列表:
path:文件路径
mode:打开文件的方式,共计6种,分别是:
-
r:以只读的方式打开文件,并且文件位置指针会被定位到文件首。如果要打开的文件不存在则报错。
-
r+:以读写的方式打开文件,并且文件位置指针会被定位到文件首。如果要打开的文件不存在则报错。
-
w:以只写的方式打开文件,如果文件不存在则创建,如果文件已存在则被截断为 0 字节,并且文件位置指针会被定位到文件首。
-
w+:以读写的方式打开文件,如果文件不存在则创建,如果文件已存在则被截断为 0 字节,并且文件位置指针会被定位到文件首。
-
a:以追加的方式打开文件,如果文件不存在则创建,且文件位置指针会被定位到文件最后一个有效字符的后面(EOF,end of the file)。
-
a+:以读和追加的方式打开文件,如果文件不存在则创建,且读文件位置指针会被初始化到文件首,但是总是写入到最后一个有效字符的后面(EOF,end of the file)。
2.2 fgetc/fgets
#include <stdio.h>
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
fgets 并没有解决 gets 函数会导致缓冲区溢出的问题,而是指定缓冲区字节长度来避免多读入数据。当遇到以下四种情况时会返回:(1)数据读入量达到 n-1;(2)读入字符遇到 \n时;(3)读入字符遇到EOF时;(4)读取遇到错误时; 它会在读取到的数据的最后面添加一个 \0 到s中。
2.3 fread/fwrite
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数列表:
-
ptr:fread(3) 将从 stream 中读取出来的数据回填到 ptr 所指向的位置;fwrite(3) 则将从 ptr 所只想的位置读取数据写入到 stream 中;
-
size:要读取的每个对象所占用的字节数;
-
nmemb:要读取出多少个对象;
-
stream:数据来源或去向;
注意 fread/fwrite 分别返回成功读写对象的个数,而不是字节数。这两个函数有以下两种常见的用法:
(1)读或写一个二进制数组。
float data[10];
if (fwrite(&data[2], sizeof(float), 4, fp) != 4)
err_sys("write error")
(2)读或写一个结构体
struct {
short count;
long total;
char name[MAXSIZE];
} item;
if (fwrite(&item, sizeof(item), 1, fp) != 1)
err_sys("write error")
2.4 fseek/ftell
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
ftell用于返回当前文件指针的偏移量,fseek定位一个文件指针的位置,rewind将文件指针定位到文件开头。
3、临时文件
#include<stdio.h>
char *tmpnam(char *ptr);
FILE *tmpfile(void);
tmpname 函数产生一个与现有文件名不同的一个有效路径名字符串,每次调用都将产生一个不同的路径。
tmpfile 函数创建一个临时的二进制文件,在关闭该文件或者程序结束时将自动删除这种文件。UNIX 对二进制文件不进行特殊区分。
tmpfile 常用的标准UNIX技术是先调用 tmpnam 产生一个唯一路径名,然后用该路径名创建一个文件,并立即 unlink 它。因为对于一个文件 unlink 并不会删除其内容,关闭该文件时才会删除其内容。
int main(void) {
char name[L_tmpnam], line[MAXLINE];
FILE *fp;
printf("%s\n", tmpnam(NULL));
tmpnam(name);
if ((fp = tmpfile()) == NULL)
err_sys("tmpfile error");
fputs("one line of output\n", fp);
rewind(fp);
if (fgets(line, sizeof(line), fp) == NULL)
err_sys("fgets error");
fputs(line, stdout);
exit(0);
}
#include <stdlib.h>
char *mkdtemp(char *template);
int mkstemp(char *template);
mkdtemp 创建临时目录并返回指向目录名的指针;mkstemp 创建临时目录并返回指向目录名的文件描述符。