- 实现
每个标准I/O流都有一个相关联的文件描述符,可以用fileno函数来获取。
#include<stdio.h>
int fileno(FILE* fp); //POSIX支持的扩展,函数dup和fcntl需要此函数
由范例可看出流连接到终端时是行缓冲one line to standard error stream = stdin, line buffered, buffer size = 1024 stream = stdout, line buffered, buffer size = 1024 stream = stderr, unbuffered, buffer size = 1 stream = /etc/passwd, fully buffered, buffer size = 4096
而当流定向到文件时
流变为了全缓冲,标准错误仍然不带缓冲stream = stdin, fully buffered, buffer size = 4096 stream = stdout, fully buffered, buffer size = 4096 stream = stderr, unbuffered, buffer size = 1 stream = /etc/passwd, fully buffered, buffer size = 4096
- 临时文件
#include<stdio.h>
char* tmpnam(char* ptr); //返回路径
FILE* tmpfile(); //返回文件指针,错误返回NULL
tmpnam产生的路径放在静态区,若需多次使用该路径应该保存路径副本,重复调用tmpnam会覆盖静态区。
tmp创建临时二进制文件(wb+),在关闭文件或程序终止时自动删除。
输出char name[L_tmpnam], line[MAXLINE]; FILE* fp; printf("%s\n", tmpnam(NULL)); tmpnam(name); printf("%s\n", name); FILE* fp2; if((fp2 = fopen(name, "r+")) == NULL) err_sys("fopen error"); 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);
/tmp/fileC9o7x4 /tmp/fileojVsqW fopen error: No such file or directory
可以看到tmpnam产生的路径名已经不能再打开,因为使用tmpnam后会立即unlink它(解除链接而不删除内容)。
同时在编译时有如下提示
事实上XSI扩展部分定义了另外两个函数mkdtemp和mkstemp/tmp/cc57tA4p.o:在函数‘main’中: 5.13.cpp:(.text+0x21): 警告: the use of `tmpnam' is dangerous, better use `mkstemp'
char* mkdtemp(char* template); //成功返回目录路径,出错返回NULL
int mkstemp(char* template); //成功返回文件描述符,出错返回-1
template是后6位设置为XXXXXX的路径名,函数将占位符替换成随机字符来构建文件名或目录名。
mkstemp返回文件描述符并以读写方式打开,而且不同于tempfile,此临时文件并不会自动删除。
tmpnam和tempnam在返回路径名和创建文件间有时间差,在这之间该路径名可能被占用,所以推荐使用tmpfile和mkstemp。
- 内存流
创建内存流的函数
#include<stdio.h>
FILE* fmemopen(void* restrict buf, size_t size, const char* restrict type);
成功返回流指针,错误返回NULL。buf为空时,分配size字节的缓冲,这样在关闭流时缓冲区被释放。
以追加方式打开内存流时,当前文件位置设为缓冲区的第一个null字节,若没有则设为缓冲区结尾的后一个字节。如果不是以追加方式打开时,当前位置设为缓冲区开始位置。
增加流缓冲区中数据量以及调用fclose,fflush,fseek,fseeko,fsetpos都会在当前位置写入一个null字节。
还有两个函数是
#include<stdio.h>
FILE* open_memstream(char** bufp, size_t* sizep); //面向字节
#include<wchar.h>
FILE* open_wmemstream(wchar_t** bufp, size_t* sizep); //面向宽字节
不同于fmemopen,
- 这两个只能以写打开
- 不能指定自己的缓冲区,但可以通过bufp和sizep来访问缓冲区的地址和大小
- 关闭流后需手动释放缓冲区
- 对流添加字节会增加缓冲区大小
缓冲区调整后需调用fclose或fflush才能生效,并且只在下次写入或fclose前才有效,因为缓冲区的增长可能重新分配内存。内存流适合创建字符串,把流作为参数用于临时文件的函数,可以大大提高性能。