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);
}
评论区