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/。

