Конвертировать ответ сервера (std :: string) в png файл - PullRequest
0 голосов
/ 10 октября 2011

Я получаю ответ от сервера, использующего 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-адреса.использование int x=write_to_binary_file(response.c_str());

по-прежнему не будет работать для меня; (

Ответы [ 4 ]

3 голосов
/ 10 октября 2011
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() ... и stop думаю, кодирование .


Кроме того, я сомневаюсь, что это компилируется:

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)

Строки - это объекты, а не необработанные массивы!

1 голос
/ 10 октября 2011

Возможно, вы захотите использовать SFML для такой задачи, учитывая, что работает с HTTP и значительно упрощает задачу.Я лично использовал его для загрузки изображений .GIF с веб-сайта.

Чтобы ответить на ваш вопрос (по общему признанию, я не знаком с boost :: asio), вы должны рассмотреть следующие вопросы:

  1. Не делайте sizeof (std :: string).Std :: string имеет метод .size ().Итак response.size ();здесь применимо.

  2. Не используйте strlen (), sizeof () или любой метод, который использует значение Sentinel с нулевым символом в конце при работе с необработанными данными с веб-сайта как ноль-значение может встречаться в любом месте в потоке необработанных данных (это не похоже на текст).Используйте метод std :: string .size ().

  3. При наличии необработанных данных пишите в двоичном режиме!Текстовый режим завершается при сигнале ctrl + z в файле в Windows.То есть, скорее всего, файл будет записан не полностью.

  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);
1 голос
/ 10 октября 2011

Мое первое предположение было бы, что "reinterpret_cast (& p_Data)" портит ваши данные. Почему ты так разыгрываешь? p_Data.data () или p_Data.c_str (), вероятно, то, что вы хотите.

0 голосов
/ 10 октября 2011

посмотрите, что является содержимым вашей строки ответа. вероятно, вам следует декодировать его с помощью декодера base64 перед записью в файл

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...