【问题标题】:Creating a FILE * stream that results in a string创建产生字符串的 FILE * 流
【发布时间】:2010-12-17 00:08:02
【问题描述】:

我正在寻找一种将FILE * 传递给某个函数的方法,以便该函数可以使用fprintf 对其进行写入。例如,如果我希望输出出现在磁盘上的实际文件中,这很容易。但我想要的是将所有输出作为字符串 (char *)。我想要的 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);

glibc 标头似乎表明可以使用挂钩函数设置 FILE 来执行实际的读取和写入。就我而言,我想我希望写钩子将字符串的副本附加到链接列表中,并且有一个 get_string_buffer 函数来计算列表的总长度,为其分配内存,然后复制将每个项目放入正确的位置。

我的目标是可以传递给诸如do_some_stuff 之类的函数的东西,而该函数不需要知道任何东西,除了它有一个可以写入的FILE *

是否有这样的现有实现?这似乎是一件有用且对 C 友好的事情——假设我对 FILE 可扩展性的看法是正确的。

【问题讨论】:

    标签: c string file stream printf


    【解决方案1】:

    如果便携性对您来说不重要,您可以查看fmemopenopen_memstream。它们是 GNU 扩展,因此仅在 glibc 系统上可用。尽管它们看起来像是 POSIX.1-2008 的一部分(fmemopenopen_memstream)。

    【讨论】:

    • open_memstream 正是我想要的。我不确定它是否使用了链表方法,但我不会向它写入大量数据,所以没关系。
    【解决方案2】:

    我不确定是否可以不可移植地扩展 FILE 对象,但如果您正在寻找更适合 POSIX 的东西,您可以使用 pipefdopen

    它与从缓冲区返回字节的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 */
    }
    

    从那里您将希望使用write() 将缓冲区写入fd[1]。但是,请小心执行此步骤,因为如果管道的缓冲区已满(即有人需要读取另一端),write() 可能会阻塞,并且如果您的进程在写入时收到信号,您可能会收到EINTR。还要注意SIGPIPE,当另一端关闭管道时会发生这种情况。也许为了您的使用,您可能希望在单独的线程中执行缓冲区的write,以避免阻塞并确保您处理SIGPIPE

    当然,这不会创建可搜索的FILE*...

    【讨论】:

      【解决方案3】:

      我不确定我理解你为什么要搞乱 FILE *.难道你不能简单地写入一个文件,然后将它加载到字符串中吗?

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

      如果您只想将格式化文本“写入”字符串,另一种选择可能是使用 snprintf() 处理可扩展缓冲区(有关如何处理此问题的建议,请参阅此 SO 问题的答案:Resuming [vf]?nprintf after reaching the limit )。

      相反,如果您想创建一个可以透明地传递给任何采用FILE * 的函数以使它们作用于字符串缓冲区的类型,那么这将是一件复杂得多的事情...

      【讨论】:

      • 有充分的理由想要这样一个FILE*:有很多库只提供基于FILE* 的I/O,并坚持在数据可能已经可用时读取文件在记忆中。因此,最好能够传递内存缓冲区,而不是只为这些库写入文件。不幸的是,这些库很少(如果有的话)提供它们的 FILE* 相关 API 的替代方案。
      猜你喜欢
      • 2012-05-11
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 1970-01-01
      • 2014-05-04
      相关资源
      最近更新 更多