FOPENCOOKIE - Linux手册页
Linux程序员手册 第3部分
更新日期: 2020-04-11
名称
fopencookie-打开自定义流
语法
#define _GNU_SOURCE /* See feature_test_macros(7) */ #include <stdio.h> FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs);
说明
fopencookie()函数允许程序员为标准I / O流创建自定义实现。该实现可以将流的数据存储在其自己选择的位置。例如,fopencookie()用于实现fmemopen(3),它为存储在内存缓冲区中的数据提供流接口。
为了创建自定义流,程序员必须:
- *
- 实现在流上执行I / O时由标准I / O库内部使用的四个"挂钩"函数。
- *
- 定义" cookie"数据类型,该结构提供由上述挂钩函数使用的簿记信息(例如,存储数据的位置)。标准I / O程序包对此cookie的内容一无所知(因此在传递给fopencookie()时将其键入为void *),但是在调用hook函数时会自动将cookie作为第一个参数提供。
- *
- 调用fopencookie()打开一个新流,并将cookie和hook函数与该流关联。
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
- 此函数实现流的读取操作。调用时,它将接收三个参数:
- ssize_t read(void * cookie,char * buf,size_t size);
- buf和size参数分别是一个可以放置输入数据的缓冲区和该缓冲区的大小。作为函数结果,读取函数应返回复制到buf中的字节数,在文件末尾返回0,在错误时返回-1。读取功能应适当更新流偏移量。
- 如果* read是空指针,则从自定义流中读取的内容始终返回文件末尾。
- cookie_write_function_t *write
- 该函数实现流的写操作。调用时,它将接收三个参数:
- ssize_twrite(void * cookie,const char * buf,size_t size);
- buf和size参数分别是要输出到流中的数据缓冲区和该缓冲区的大小。作为函数结果,写函数应返回从buf复制的字节数,如果出错则返回0。 (该函数不得返回负值。)写函数应适当更新流偏移量。
- 如果* write为空指针,则丢弃流的输出。
- cookie_seek_function_t *seek
- 此函数在流上实现查找操作。调用时,它将接收三个参数:
- intseek(void * cookie,off64_t * offset,int);
- The
*offset
argument specifies the new file offset depending on which
of the following three values is supplied in
whence:- SEEK_SET
- 流偏移量应从流的开始处设置* offset字节。
- SEEK_CUR
- * offset应该添加到当前流的偏移量中。
- SEEK_END
- 流偏移量应设置为流的大小加* offset。
- 返回之前,seek函数应更新* offset以指示新的流偏移量。
- 作为其函数结果,seek函数在成功时应返回0,在错误时应返回-1。
- 如果* seek是空指针,则无法在流上执行搜索操作。
- cookie_close_function_t *close
- 此功能关闭流。挂钩函数可以执行一些操作,例如释放为流分配的缓冲区。调用时,它接收一个参数:
- int close(无效* cookie);
- cookie参数是程序员调用fopencookie()时提供的cookie。
- 作为函数结果,关闭函数成功应返回0,错误则返回EOF。
- 如果* close为NULL,则在关闭流时不执行任何特殊操作。
返回值
成功的话,fopencookie()返回一个指向新流的指针。错误时,返回NULL。
属性
有关本节中使用的术语的说明,请参见attribute(7)。
Interface | Attribute | Value |
fopencookie() | Thread safety | MT-Safe |
遵循规范
此函数是非标准的GNU扩展。
示例
下面的程序实现了一个自定义流,其功能与fmemopen(3)相似(但不相同)。它实现了一个流,其数据存储在内存缓冲区中。该程序将其命令行参数写入流,然后在流中搜索,每五个字符中读取两个,并将它们写入标准输出。以下shell会话演示了该程序的用法:
$ ./a.out aqhello worldaq /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; ssize_t nread; long p; int j; 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 (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 (p = 0; ; p += 5) { if (fseek(stream, p, SEEK_SET) == -1) { perror("fseek"); exit(EXIT_FAILURE); } nread = fread(buf, 1, 2, stream); if (nread == -1) { perror("fread"); exit(EXIT_FAILURE); } if (nread == 0) { printf("Reached end of file\n"); break; } printf("/%.*s/\n", nread, buf); } exit(EXIT_SUCCESS); }
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。