文章目录
内存流
三个用于内存流的创建,第一个是fmemopen
函数。
#include <stdio.h>
FILE *fmemopen(void *restrict buf, size_t size, const char *restrict type);
返回值:若成功,返回流指针;若错误,返回NULL。
fmemopen
函数允许调用者提供缓冲区用于内存流:
buf
参数指向缓冲区的开始位置;size
参数指定了缓冲区大小的字节数。如果buf
参数为空,fmemopen
函数分配size
字节数的缓冲区。在这种情况下,当流关闭时缓冲区会被释放。
type参数的可能取值如下表:
type | 说明 |
---|---|
r或rb | 为读而打开 |
w或wb | 为写而打开 |
a或ab | 追加;为在第一个null字节处写而打开 |
r+或r+b或rb+ | 为读和写而打开 |
w+或w+b或wb+ | 把文件截断至0长,为读和写而打开 |
a+或a+b或ab+ | 追加;为在第一个null字节处读和写而打开 |
#include "../../include/apue.h"
#define BSZ 48
int main(void)
{
FILE *fp;
char buf[BSZ];
memset(buf, 'a', BSZ-2);
buf[BSZ-2] = '0';
buf[BSZ-1] = '\0';
printf("buf = %s, len of string in buf = %ld\n", buf, (long)strlen(buf));
if((fp = fmemopen(buf, BSZ, "w+")) == NULL)
err_sys("fmemopen failed");
printf("initial buffer contents: %s\n", buf);
fprintf(fp, "hello, world");
printf("before flush: %s\n", buf);
fflush(fp);
printf("after fflush: %s\n", buf);
printf("len of string in buf = %ld\n", (long)strlen(buf));
memset(buf, 'b', BSZ - 2);
buf[BSZ-2] = '\0';
buf[BSZ-1] = 'X';
fprintf(fp, "hello, world");
printf("before fseek: %s, len of string in buf = %ld\n", buf,\
(long)strlen(buf));
fseek(fp, 0, SEEK_SET);
printf("after fseek: %s\n", buf);
printf("len of string in buf = %ld\n", (long)strlen(buf));
memset(buf, 'c', BSZ-2);
buf[BSZ-2] = '\0';
buf[BSZ-1] = 'X';
fprintf(fp, "hello world");
printf("before fclose: %s, len of string in buf = %ld\n", buf,\
(long)strlen(buf));
fclose(fp);
printf("after fclose: %s\n", buf);
printf("len of string in buf = %ld\n", (long)strlen(buf));
return 0;
}
结果如下:
由上图可知,调用fflush
会在缓冲区开始处null字节;而当调用fseek
函数时,则会在末尾处追加null字节;在调用fclose
函数则不会追加写null字节。
用于创建内存流的另两个函数是open_memstream
和open_wmemstream
。
#include <stdio.h>
FILE *open_memstream(char **bufp, size_t *sizep);
#include <wchar.h>
FILE *open_wmemstream(wchar_t **bufp, size_t *sizep);
两个函数的返回值:若成功,返回流指针;若出错,返回NULL。
open_memstream
函数创建的流是面向字节的,open_wmemstream
函数创建的流是面向宽字节的。这两个函数与
fmemopen
函数不同之处在于:
- 创建的流只能写打开
- 不能指定自己的缓冲区,但可以分别通过
bufp
和sizep
参数访问缓冲区地址和大小- 关闭流之后需要自行释放缓冲区
- 对流添加字节会增加缓冲区大小
注意: 为了避免缓冲区溢出,内存流非常适用于创建字符串。因为内存流只访问主存,不访问磁盘上的文件,所以对于标准I/O流作为参数用于临时文件的函数来说,会有很大的性能提升。
测试示例:
#include "../../include/apue.h"
#include <wchar.h>
#define MAXSIZE 40
void test1()
{
FILE *fp;
char *buf = (char *)malloc(MAXSIZE*sizeof(char));
memset(buf, 'a', MAXSIZE-2);
buf[MAXSIZE-2] = '\0';
buf[MAXSIZE-1] = 'X';
printf("buf = \"%s\", len = %ld\n", buf, (long)strlen(buf));
size_t size = MAXSIZE;
if((fp = open_memstream(&buf, &size)) == NULL)
err_sys("open_memstream error");
fprintf(fp, "hello, world");
printf("before flush buf = \"%s\", len = %ld\n", buf, (long)strlen(buf));
fflush(fp);
printf("after flush buf = \"%s\", len = %ld\n", buf, (long)strlen(buf));
}
int main()
{
test1();
return 0;
}
结果如下:
由上图可知,缓冲区地址和大小使用上必须遵循一些规则。
第一,只有在调用了
fclose
或fflush
后,缓冲区地址与长度才有有效;第二,这些值只有在下一次l流写入或调用
fclose
前才有效。