将服务器响应(std::string)转换为png文件

Convert server response (std::string) into a png file

本文关键字:转换 png 文件 string 响应 std 服务器      更新时间:2023-10-16

我正在使用boost::asio从服务器获得响应。结果存储在std::字符串中。

我想将这个std::字符串转换为.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()); 呼叫

仍然对我不起作用;(

binary_file.write(reinterpret_cast<const char*>(&p_Data),sizeof(std::string));

没错,这就是reinterpret_cast在许多情况下表现不佳的原因:它促进了猜测

这是指您扔掉了参考资料,只是假设需要将指向std::string的指针传递到某个位置,并确定编译器的错误消息是错误的。所以,你用reinterpret_cast来"闭嘴",现在你想知道为什么什么都不能正常工作。

大概有人告诉你"使用std::string"而不是字符数组,你只是交换了类型名,而不是研究实际的差异是什么。

std::string是一个具有各种内部成员的对象,通常间接存储其实际字符串数据(动态地,或者您可能不准确和误导地称之为"堆上"的数据(;事实上,它完全是从你那里抽象出来的,它是如何存储数据的。无论哪种方式,它都不仅仅是一个char数组。

使用它提供的API获取指向char数组的指针,其中包含std::string::data()或可能包含std::string::c_str()。。。别再胡搅蛮缠了。


此外,我怀疑这是否编译:

std::string errorBuffer[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);

你可能想构建一个具有一定长度的std::string

std::string errorBuffer(CURL_ERROR_SIZE);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorBuffer[0]);
// ^ (requires C++11 to be completely safe)

字符串是对象,而不是原始数组

我的第一个猜测是"interpret_cast(&p_Data("弄乱了你的数据。你为什么这样选?p_Data.Data((或p_Data.c_str((可能是您想要的。

您可能需要考虑将SFML用于此类任务,因为它处理HTTP并大大简化了任务。我个人用它下载。GIF图片从一个网站。

为了解决您的问题(无可否认,我不熟悉boost::asio(,您需要考虑的是:

  1. 不要执行sizeof(std::string(。Std::string有一个.size((方法。所以response.size((;适用于此处。

  2. 在处理来自网站的原始数据时,不要使用strlen((、sizeof((或任何使用以null结尾的sentinel值的方法,因为null值可能出现在原始数据流中的任何位置(它不像文本(。使用std::string的.size((方法。

  3. 如果它是原始数据,请以二进制模式写入!文本模式将在windows上的文件中的ctrl+z信号时终止。IE可能无法完全写入文件。

  4. Base64并不总是适用。无论如何,这很可能是自动化的。

  5. 请考虑从提供的URL本身提取文件名。

假设响应是可接受的,这就是您想要的代码:

FILE * File = NULL;
File = fopen("Image.png","wb"); //Note b for binary mode
if(File == NULL){return 1;} //Error
if(fwrite(response.c_str(),response.size(),1,File) != response.size()) //If there is a mismatch between the amount of data written and the string size, we have an error
{
    perror("File write error occurred"); //Needs errno
    fclose(File);
    return 2;
}
fclose(File);

查看响应字符串的内容。在写入文件

之前,您可能应该使用base64解码器对其进行解码