html - 在不使用 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;
}
解决方案
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
(为简洁起见,省略了所有错误检查。)
这使您无需手动跟踪大小,并为您提供动态增长的后备缓冲区,以便您可以以合理的内存效率处理大小输出。
推荐阅读
- java - 如何将发件人的消息放在左侧,将收件人的消息放在右侧
- reactjs - 我正在尝试在 React js 中创建一个 onDimiss 按钮
- go - Kafka 消息未传递给消费者
- c# - Xamarin - 智能手机内存中的存储数据
- php - laravel 属于不使用一对一关系
- php - PHP preg_replace 用html替换通配符字符串以及通配符之后会发生什么
- node.js - 如何使用 Create-React-App 的节点服务器定义 MIME 类型?
- tensorflow - 如何在张量流中为我的网络提供正确的数组大小
- r - 按其各自的级别对数据框的列进行子集化,并将函数应用于每个子集
- spring - 从静态字段中设置 spring 中的属性值