侧边栏壁纸
博主头像
noerror

虚灵不寐,众理具而万事出。

  • 累计撰写 239 篇文章
  • 累计创建 9 个标签
  • 累计收到 2 条评论
标签搜索

目 录CONTENT

文章目录

fopencookie函数用法详解

noerror
2022-10-04 / 0 评论 / 0 点赞 / 42 阅读 / 1,953 字 / 正在检测是否收录...

fopencookie函数用法详解

fopencookie函数简介

  • 头文件包含
#include <stdio.h>
  • 函数定义
FILE *fopencookie(void * cookie , const char * mode ,
                  cookie_io_functions_t  io_funcs );

fopencookie函数常见使用错误

  • 编译错误
    warning: implicit declaration of function ‘fopencookie’ [-Wimplicit-function-declaration]
    解决办法:包含头文件
#include <stdio.h>

fopencookie函数详细描述

fopencookie ()函数允许程序员为标准I/O流创建自定义实现。这个实现可以将流的数据存储在它自己选择的位置;例如,fopencookie ()用于实现fmemopen (3),它为存储在内存缓冲区中的数据提供流接口。
为了创建自定义流,程序员必须:

  • 实现标准I/O库在流上执行I/O时在内部使用的四个“挂钩”函数。
  • 定义一个“cookie”数据类型,一个提供上述钩子函数使用的簿记信息(例如,在哪里存储数据)的结构。标准I/O包对此cookie的内容一无所知(因此,当传递给fopencookie ())时,它被类型化为"void\ *",但在调用钩子函数时,它会自动将cookie作为第一个参数提供。
  • 调用fopencookie ()打开一个新流,并将cookie和钩子函数与该流关联起来。

fopencookie ()函数的作用与fopen (3):类似,它打开一个新流,并返回一个指向用于对该流进行操作的FILE对象的指针。
cookie参数是指向调用方的cookie结构的指针,该结构将与新流关联。当标准I/O库调用下面描述的任何钩子函数时,该指针将作为第一个参数提供。
mode参数的作用与fopen (3)相同,支持以下模式:r ,w ,a ,r+ ,w+ 和a+ ,详细信息请参阅fopen (3)。
io_funcs参数是一个包含四个字段的结构,这些字段指向程序员定义的钩子函数,这些钩子函数用于实现这个流。该结构定义如下

typedef struct {
   cookie_read_function_t  *read;
   cookie_write_function_t *write;
   cookie_seek_function_t  *seek;
   cookie_close_function_t *close;
} cookie_io_functions_t;

这四个领域如下:

  • cookie_read_function_t read此函数实现流的读操作。当被调用时,它会收到三个参数:.ip ssize_t read(voidcookie,charbuf,size_t size);.ip buf和size参数分别是一个可以放置输入数据的缓冲区,以及该缓冲区的大小。作为它的函数结果,read函数应该在文件结束时返回复制到buf 0中的字节数,或者在错误时返回-1。read函数应该适当地更新流偏移量。.ip如果read是空指针,则从自定义流中读取总是返回文件结尾。
  • cookie_write_function_t write此函数实现流的写操作。调用时,它会收到三个参数:.ip ssize_t write(voidcookie,const charbuf,size_t size);.ip buf和size参数分别是要输出到流的数据缓冲区和该缓冲区的大小。作为其函数结果,write函数应该返回错误时从buf 或0复制的字节数。(函数不能返回负值。)write函数应该适当地更新流偏移量。.ip如果write是空指针,则放弃对流的输出。
  • cookie_seek_function_t seek此函数在流上实现查找操作。当被调用时,它接收三个参数:.ip int seek(voidcookie,off64_t*offset,int whence);*offset参数指定新文件偏移量,这取决于whence :.rs中提供的以下三个值中的哪一个
  • SEEK_SET 流偏移量应设置为从流开始的*offset字节。
  • 应将 SEEK_CUR *offset添加到当前流偏移量。
  • SEEK_END 流偏移量应设置为流加offset .re.ip的大小,然后返回,seek函数应更新offset以指示新的流偏移量。.ip作为它的函数结果,seek函数在成功时应该返回0,在错误时返回-1。.ip如果*seek是空指针,则不可能对流执行查找操作。
  • cookie_close_function_t close此函数关闭流。钩子函数可以执行诸如释放为流分配的缓冲区之类的操作。调用时,它接收一个参数:.ip int close(voidcookie);.ip cookie参数是程序员在调用fopencookie ().ip作为其函数结果时提供的cookie,成功时close函数应返回0,错误时 EOF 函数应返回。.ip如果*close为NULL,则在流关闭时不执行任何特殊操作。

fopencookie函数返回值

成功后,fopencookie ()返回一个指向新流的指针。出错时,返回NULL。

fopencookie函数使用举例

下面的程序实现了一个自定义流,其功能与通过fmemopen (3)获得的功能相似(但不完全相同),它实现了一个数据存储在内存缓冲区中的流。程序将其命令行参数写入流,然后在流中查找,每五个字符中读取两个并将其写入标准输出。下面的shell会话演示该程序的用法:

" ./a.out \(aqhello world\(aq"
/he/
/ w/
/d/
Reached end of file

请注意,下面的程序的一个更通用的版本可以改进,以更健壮地处理各种错误情况(例如,用已经打开的流的cookie打开流;关闭已经关闭的流)。Program source&

#define _GNU_SOURCE
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define INIT_BUF_SIZE 4

struct memfile_cookie {
   char   *buf;        /* Dynamically sized buffer for data */
   size_t  allocated;  /* Size of buf */
   size_t  endpos;     /* Number of characters in buf */
   off_t   offset;     /* Current file offset in buf */
};

ssize_t
memfile_write(void *c, const char *buf, size_t size)
{
   char *new_buff;
   struct memfile_cookie *cookie = c;

   /* Buffer too small? Keep doubling size until big enough */

   while (size + cookie\->offset > cookie\->allocated) {
       new_buff = realloc(cookie\->buf, cookie\->allocated * 2);
       if (new_buff == NULL) {
           return \-1;
       } else {
           cookie\->allocated *= 2;
           cookie\->buf = new_buff;
       }
   }

   memcpy(cookie\->buf + cookie\->offset, buf, size);

   cookie\->offset += size;
   if (cookie\->offset > cookie\->endpos)
       cookie\->endpos = cookie\->offset;

   return size;
}

ssize_t
memfile_read(void *c, char *buf, size_t size)
{
   ssize_t xbytes;
   struct memfile_cookie *cookie = c;

   /* Fetch minimum of bytes requested and bytes available */

   xbytes = size;
   if (cookie\->offset + size > cookie\->endpos)
       xbytes = cookie\->endpos \- cookie\->offset;
   if (xbytes < 0)     /* offset may be past endpos */
      xbytes = 0;

   memcpy(buf, cookie\->buf + cookie\->offset, xbytes);

   cookie\->offset += xbytes;
   return xbytes;
}

int
memfile_seek(void *c, off64_t *offset, int whence)
{
   off64_t new_offset;
   struct memfile_cookie *cookie = c;

   if (whence == SEEK_SET)
       new_offset = *offset;
   else if (whence == SEEK_END)
       new_offset = cookie\->endpos + *offset;
   else if (whence == SEEK_CUR)
       new_offset = cookie\->offset + *offset;
   else
       return \-1;

   if (new_offset < 0)
       return \-1;

   cookie\->offset = new_offset;
   *offset = new_offset;
   return 0;
}

int
memfile_close(void *c)
{
   struct memfile_cookie *cookie = c;

   free(cookie\->buf);
   cookie\->allocated = 0;
   cookie\->buf = NULL;

   return 0;
}

int
main(int argc, char *argv[])
{
   cookie_io_functions_t  memfile_func = {
       .read  = memfile_read,
       .write = memfile_write,
       .seek  = memfile_seek,
       .close = memfile_close
   };
   FILE *stream;
   struct memfile_cookie mycookie;
   size_t nread;
   char buf[1000];

   /* Set up the cookie before calling fopencookie() */

   mycookie.buf = malloc(INIT_BUF_SIZE);
   if (mycookie.buf == NULL) {
       perror("malloc");
       exit(EXIT_FAILURE);
   }

   mycookie.allocated = INIT_BUF_SIZE;
   mycookie.offset = 0;
   mycookie.endpos = 0;

   stream = fopencookie(&mycookie,"w+", memfile_func);
   if (stream == NULL) {
       perror("fopencookie");
       exit(EXIT_FAILURE);
   }

   /* Write command\-line arguments to our file */

   for (int j = 1; j < argc; j++)
       if (fputs(argv[j], stream) == EOF) {
           perror("fputs");
           exit(EXIT_FAILURE);
       }

   /* Read two bytes out of every five, until EOF */

   for (long p = 0; ; p += 5) {
       if (fseek(stream, p, SEEK_SET) == \-1) {
           perror("fseek");
           exit(EXIT_FAILURE);
       }
       nread = fread(buf, 1, 2, stream);
       if (nread == 0) {
           if (ferror(stream) != 0) {
               fprintf(stderr, "fread failed\en");
               exit(EXIT_FAILURE);
           }
           printf("Reached end of file\en");
           break;
       }

       printf("/%.*s/\en", (int) nread, buf);
   }

   exit(EXIT_SUCCESS);
}
0

评论区