简体   繁体   English

创建导致字符串的FILE *流

[英]Creating a FILE * stream that results in a string

I'm looking for a way to pass in a FILE * to some function so that the function can write to it with fprintf . 我正在寻找一种方法将FILE *传递给某个函数,以便函数可以使用fprintf写入它。 This is easy if I want the output to turn up in an actual file on disk, say. 如果我想让输出在磁盘上的实际文件中出现,这很容易。 But what I'd like instead is to get all the output as a string ( char * ). 但我想要的是将所有输出作为字符串( char * )。 The kind of API I'd like is: 我喜欢的那种API是:

/** Create a FILE object that will direct writes into an in-memory buffer. */
FILE *open_string_buffer(void);

/** Get the combined string contents of a FILE created with open_string_buffer
    (result will be allocated using malloc). */
char *get_string_buffer(FILE *buf);

/* Sample usage. */
FILE *buf;
buf = open_string_buffer();
do_some_stuff(buf);   /* do_some_stuff will use fprintf to write to buf */
char *str = get_string_buffer(buf);
fclose(buf);
free(str);

The glibc headers seem to indicate that a FILE can be set up with hook functions to perform the actual reading and writing. glibc标题似乎表明可以使用钩子函数设置FILE来执行实际的读取和写入。 In my case I think I want the write hook to append a copy of the string to a linked list, and for there to be a get_string_buffer function that figures out the total length of the list, allocates memory for it, and then copies each item into it in the correct place. 在我的情况下,我想我希望写钩子将字符串的副本附加到链表,并且有一个get_string_buffer函数,它计算出列表的总长度,为它分配内存,然后复制每个项目在正确的地方进入它。

I'm aiming for something that can be passed to a function such as do_some_stuff without that function needing to know anything other than that it's got a FILE * it can write to. 我的目标是可以传递给do_some_stuff这样的函数,而不需要知道任何东西,除了它有一个它可以写入的FILE *

Is there an existing implementation of something like this? 是否存在类似这样的现有实现? It seems like a useful and C-friendly thing to do -- assuming I'm right about the FILE extensibility. 这似乎是一个有用且C友好的事情 - 假设我对FILE可扩展性是正确的。

If portability is not important for you, you can take a look on fmemopen and open_memstream . 如果可移植性对您不重要,您可以查看fmemopenopen_memstream They are GNU extensions, hence only available on glibc systems. 它们是GNU扩展,因此只能在glibc系统上使用。 Although it looks like they are part of POSIX.1-2008 ( fmemopen and open_memstream ). 虽然看起来它们是POSIX.1-2008( fmemopenopen_memstream )的一部分。

I'm not sure if it's possible to non-portably extend FILE objects, but if you are looking for something a little bit more POSIX friendly, you can use pipe and fdopen . 我不确定是否可以非扩展地扩展FILE对象,但是如果你正在寻找更多POSIX友好的东西,你可以使用pipefdopen

It's not exactly the same as having a FILE* that returns bytes from a buffer, but it certainly is a FILE* with programmatically determined contents. 它与从缓冲区返回字节的FILE*不完全相同,但它肯定是具有编程确定内容的FILE*

int fd[2];
FILE *in_pipe;

if (pipe(fd))
{
   /* TODO: handle error */
}

in_pipe = fdopen(fd[0], "r");
if (!in_pipe)
{
   /* TODO: handle error */
}

From there you will want to write your buffer into fd[1] using write() . 从那里你将需要使用write()将缓冲区写入fd[1] Careful with this step, though, because write() may block if the pipe's buffer is full (ie someone needs to read the other end), and you might get EINTR if your process gets a signal while writing. 但是,请小心这一步,因为如果管道的缓冲区已满(即有人需要读取另一端), write()可能会阻塞,如果您的进程在写入时获得信号,您可能会获得EINTR Also watch out for SIGPIPE , which happens when the other end closes the pipe. 还要注意SIGPIPE ,当另一端关闭管道时会发生这种情况。 Maybe for your use you might want to do the write of the buffer in a separate thread to avoid blocking and make sure you handle SIGPIPE . 也许为了您的使用,您可能希望在单独的线程中write缓冲区以避免阻塞并确保您处理SIGPIPE

Of course, this won't create a seekable FILE* ... 当然,这不会创建一个可搜索的FILE* ...

I'm not sure I understand why you want to mess up with FILE *. 我不确定我理解你为什么要搞乱FILE *。 Couldn't you simply write to a file and then load it in string? 难道你不能简单地写一个文件然后用字符串加载它吗?

 char *get_file_in_buf(char *filename) {
   char *buffer;
   ... get file size with fseek or fstat ...
   ... allocate buffer ...
   ... read buffer from file ...
   return buffer;
 }

If you only want to "write" formatted text into a string, another option could be to handle an extensible buffer using snprintf() (see the answers to this SO question for a suggestion on how to handle this: Resuming [vf]?nprintf after reaching the limit ). 如果您只想将格式化文本“写入”字符串,另一个选项可能是使用snprintf()处理可扩展缓冲区(请参阅此SO问题的答案以获取有关如何处理此问题的建议: 恢复[vf]?nprintf达到极限后 )。

If, instead, you want to create a type that can be passed transparently to any function taking a FILE * to make them act on string buffers, it's a much more complex matter ... 相反,如果你想创建一个可以透明地传递给任何带有FILE *函数来使它们对字符串缓冲区起作用的类型,那么这是一个复杂得多的问题......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM