首页 > 解决方案 > 在不使用 FILE 的情况下在 C 中缓冲输出

问题描述

我正在尝试使用尽可能简单的内容长度正确大小的 HTTP 标头创建完整的 HTML 结果。

我查看了 setbuf() 函数,但它仅适用于流,但我想直接将输出缓冲到内存而不涉及磁盘。有没有更简单的功能可以实现我想要实现的功能?

我知道在 php 中,可以使用 ob_start() 开始缓冲数据并使用 ob_get_contents() 将数据加载到内存中并确定大小,那么在 C 中我可以使用类似的东西吗?

int main(){
    char *mybuf=malloc(1048576); //Allocate 1MB memory for buffer
    char *mytitle="Webpage title";
    char *mydesc="This is a page version";
    int myver=2;
    //print HTTP header of known data
    printf("HTTP/1.1 200 OK\r\n");
    printf("Server: Something\r\n");
    printf("Content-type: text/html; charset=UTF-8\r\n");
    printf("Cache-control: no-cache\r\n");
    //Buffer HTML output to get size (we don't print these 4 lines yet)
    sprintf(mybuf,"<html><head><title>%s</title></head><body>\r\n",mytitle);
    sprintf(mybuf+strlen(mybuf),"<h1>%s</h1>\r\n",mytitle);
    sprintf(mybuf+strlen(mybuf),"<p>%s %d</p>\r\n",mydesc,myver);
    sprintf(mybuf+strlen(mybuf),"</body></html>\r\n");
    //Print content length header with size of buffered data
    printf("Content-length: %d\r\n",strlen(mybuf));
    //then print the rest of the data
    printf("%s",mybuf);
    free(mybuf);
    return 0;
}

标签: htmlcmemorystreambuffer

解决方案


C 语言规范没有为仅由内存支持的流定义任何工具,没有任何底层文件。您sprintf()的基于方法还不错,但可以通过捕获和使用返回值来改进它,它告诉您打印了多少个字符。您可以使用它来避免所有strlen()调用,如果内容很大,尤其是打印成许多小块时,这可能会节省大量资金:

size_t total_bytes_written = 0;
long rval;

rval = sprintf(mybuf, "<html><head><title>%s</title></head><body>\r\n", mytitle);
if (rval < 0) {
    // handle error ...
}
total_bytes_written += rval;

rval = sprintf(mybuf + total_bytes_written, "<h1>%s</h1>\r\n", mytitle);
// ...

或者,如果您使用的是符合 POSIX.1-2008 或更高版本的系统,并且您愿意将您的程序限制为此类系统,那么您可能会open_memstream()感兴趣。这为您提供了一个由动态管理的内存块支持的流。您可以使用或其他流 IO 函数对其进行写入,fprintf()完成后,读回指向数据的指针和总大小。像这样的东西:

char *buf_ptr = NULL;
size_t buf_size = 0;
FILE *mem = open_memstream(&buf_ptr, &buf_size);

fprintf(mem, "<html><head><title>%s</title></head><body>\r\n", mytitle);
fprintf(mem, "<h1>%s</h1>\r\n", mytitle);

// ...

fclose(mem);  // mandatory
printf("Content-length: %d\r\n", buf_size);
printf("%s", buf_ptr);  // the data are guaranteed null-terminated
free(buf);  // you are responsible for this

(为简洁起见,省略了所有错误检查。)

这使您无需手动跟踪大小,并为您提供动态增长的后备缓冲区,以便您可以以合理的内存效率处理大小输出。


推荐阅读