将服务器响应 (std::string) 转换为 png 文件
我使用 boost::asio 从服务器收到响应。结果存储在 std::string 中。
我想将此 std::string 转换为 .png 图像并将其写入文件。
我在这方面遇到了很大的麻烦。这是我的代码:
CURL *curl;
CURLcode res;
std::string errorBuffer[CURL_ERROR_SIZE];
std::string url="http://www.google.ie/images/srpr/logo3w.png";
std::string response="";
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res=curl_easy_perform(curl);
curl_easy_cleanup(curl);
现在响应存储在 response
中
write_to_binary_file(response.data());
,其中 write_to_binary_file 是:
void write_to_binary_file(std::string p_Data){
//std::fstream binary_file("./img.png",std::ios::out|std::ios::binary|std::ios::app);
//binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));
//binary_file.close();
std::ofstream file("img.png", std::ios::binary);
file.write(p_Data,sizeof(p_Data));
file.close();
}
现在,如果我对 C++ 程序编写的文件执行八进制转储,它与我下载时得到的八进制转储完全不同直接从 URL 获取文件。
更新了 write_to_binary_file
int write_to_binary_file(const char* p_Data){
//std::fstream binary_file("./img.png",std::ios::out|std::ios::binary|std::ios::app);
//binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));
//binary_file.write(c_str(),sizeof(ring));
//binary_file.close();
/*std::ofstream file("img.png", std::ios::binary);
file.write(p_Data,len);
file.close();*/
FILE *fp;
size_t count;
const char *str = p_Data;
fp = fopen("img.png", "w");
if(fp == NULL) {
perror("failed to open img.png");
return EXIT_FAILURE;
}
count = fwrite(str, 1, strlen(str), fp);
printf("Wrote %zu bytes. fclose(fp) %s.\n", count, fclose(fp) == 0 ? "succeeded" : "failed");
return EXIT_SUCCESS;
}
使用 int x=write_to_binary_file(response.c_str());
调用,但仍然对我不起作用;(
I'm getting a response from a server using boost::asio. The result is stored in a std::string.
I want to convert this std::string into a .png image and write it to file.
I'm having awful trouble with this. Here is my code:
CURL *curl;
CURLcode res;
std::string errorBuffer[CURL_ERROR_SIZE];
std::string url="http://www.google.ie/images/srpr/logo3w.png";
std::string response="";
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res=curl_easy_perform(curl);
curl_easy_cleanup(curl);
response now stored in response
write_to_binary_file(response.data());
, where write_to_binary_file is:
void write_to_binary_file(std::string p_Data){
//std::fstream binary_file("./img.png",std::ios::out|std::ios::binary|std::ios::app);
//binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));
//binary_file.close();
std::ofstream file("img.png", std::ios::binary);
file.write(p_Data,sizeof(p_Data));
file.close();
}
Now if I do an octal dump on the file written by my C++ program, it's totally different to the octal dump I get when I download the file from the URL directly.
Updated write_to_binary_file
int write_to_binary_file(const char* p_Data){
//std::fstream binary_file("./img.png",std::ios::out|std::ios::binary|std::ios::app);
//binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));
//binary_file.write(c_str(),sizeof(ring));
//binary_file.close();
/*std::ofstream file("img.png", std::ios::binary);
file.write(p_Data,len);
file.close();*/
FILE *fp;
size_t count;
const char *str = p_Data;
fp = fopen("img.png", "w");
if(fp == NULL) {
perror("failed to open img.png");
return EXIT_FAILURE;
}
count = fwrite(str, 1, strlen(str), fp);
printf("Wrote %zu bytes. fclose(fp) %s.\n", count, fclose(fp) == 0 ? "succeeded" : "failed");
return EXIT_SUCCESS;
}
Call using int x=write_to_binary_file(response.c_str());
Still won't work for me ;(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,这就是为什么
reinterpret_cast
在很多场景下表现不佳:它促进了猜测编码。这是当您扔掉参考资料并假设您需要在某处传递一个指向
std::string
的指针,并确定编译器的错误消息是错误的时。因此,您使用了reinterpret_cast
来“闭嘴”,现在您想知道为什么没有任何东西可以正常工作。大概有人告诉您“使用
std::string
”而不是 char 数组,而您只是交换了类型名称,而不是对实际情况进行任何研究区别在于。std::string
是一个具有各种内部成员的对象,通常间接存储其实际字符串数据(动态地,或者您可能不准确且误导性地称为“在堆上”);事实上,它对于如何存储数据来说是完全抽象的。不管怎样,它不仅仅是一个char
数组。使用它提供的 API 获取指向
char
数组的指针,使用std::string::data()
或可能std::string: :c_str()
...以及停止猜测编码。另外,我怀疑这是否可以编译:
并且您可能想构造一个具有一定长度的
std::string
:字符串是对象,而不是原始数组!
Right, this is why
reinterpret_cast
is poor in many scenarios: it promotes guesscoding.This is when you've thrown away your reference materials and just assumed that you need to pass a pointer to an
std::string
somewhere, and decided that the compiler's error messages were wrong. So, you usedreinterpret_cast
to "shut it up", and now you're wondering why nothing's working properly.Presumably somebody has told you to "use
std::string
" instead of char arrays, and you've just swapped the type names rather than doing any research into what the actual difference is.std::string
is an object with various internal members, and which usually stores its actual string data indirectly (dynamically, or what you may inaccurately and misleadingly refer to as "on the heap"); in fact, it's completely abstracted away from you as to just how it stores its data. Either way, it's not just achar
array.Use the API that it provides to obtain a pointer to a
char
array, with eitherstd::string::data()
or possiblystd::string::c_str()
... and stop guesscoding.Also, I doubt that this compiles:
And you probably wanted to construct a
std::string
with a certain length:Strings are objects, not raw arrays!
我的第一个猜测是“reinterpret_cast(&p_Data)”
弄乱了你的数据。为什么要这样投呢?
p_Data.data() 或 p_Data.c_str() 可能是您想要的。
My first guess would be that "reinterpret_cast(&p_Data)"
is messing up your data. Why do you cast it in this way?
p_Data.data() or p_Data.c_str() are probably what you want.
您可能需要考虑使用 SFML 来完成此类任务,因为 处理 HTTP 并大大简化了任务。我个人曾使用它从网站下载 .GIF 图像。
为了解决你的问题(我承认我不熟悉 boost::asio),你需要考虑的事情是:
不要做 sizeof(std::string) 。 Std::string 有一个 .size() 方法。所以response.size();此处适用。
在处理来自网站的原始数据时,不要使用 strlen()、sizeof() 或任何使用 null 终止标记值的方法,因为 null 值可能出现在任何地方原始数据流(它不像文本)。使用 std::string 的 .size() 方法。
鉴于它是原始数据,请以二进制模式写入!在 Windows 上,文本模式将在文件内的 ctrl+z 信号上终止。 IE 可能无法完全写入文件。
Base64 并不总是适用。无论如何,这很可能是自动的。
考虑从提供的 URL 本身提取文件名。
假设响应是可以接受的,这是您想要的代码:
You might want to consider using SFML for such a task, given it deals with HTTP and greatly simplifies the task. I've personally used it download .GIF images from a website.
To address your question (I am admittedly not familiar with boost::asio), the things you will want to consider is:
Don't do sizeof(std::string). Std::string has a .size() method. So response.size(); is applicable here.
Don't use strlen(), sizeof() or any method that uses a null-terminated sentinel value when dealing with raw data from a website, as a null-value can occur anywhere in the raw data stream (it isn't like text). Use std::string's .size() method.
Given it's raw data, write in binary mode! Text mode will terminate on the ctrl+z signal within a file on windows. IE it'd likely not fully write the file.
Base64 doesn't always apply. Chances are this is automated anyway.
Consider extracting the filename from the supplied URL itself.
Assuming response is acceptable, this is the code you want:
看看你的响应字符串的内容是什么。
可能你应该在写入文件之前通过base64解码器对其进行解码
look what is the contents of your responce string.
probably you should decode it by base64 decoder before writing into file