标准I/O库之内存流

文章目录

内存流

三个用于内存流的创建,第一个是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_memstreamopen_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函数不同之处在于:

  • 创建的流只能写打开
  • 不能指定自己的缓冲区,但可以分别通过bufpsizep参数访问缓冲区地址和大小
  • 关闭流之后需要自行释放缓冲区
  • 对流添加字节会增加缓冲区大小

注意: 为了避免缓冲区溢出,内存流非常适用于创建字符串。因为内存流只访问主存,不访问磁盘上的文件,所以对于标准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;
}

结果如下:

由上图可知,缓冲区地址和大小使用上必须遵循一些规则。

第一,只有在调用了fclosefflush后,缓冲区地址与长度才有有效;

第二,这些值只有在下一次l流写入或调用fclose前才有效。

发布了229 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40073459/article/details/104403477