2012-03-08 26 views
6

he investigado en línea la mayor parte de hoy pero no he podido encontrar la respuesta, así que estoy recurriendo a stackoverflow por alguna sugerencia.cómo leer archivos de imagen y almacenarlos en la memoria (std :: string) en C++?

básicamente, tengo una biblioteca de C++ que utiliza curl para realizar el método PUT para cargar un archivo de imagen. ahora esta biblioteca toma una std :: string para datos. Tengo archivos de imagen (como jpg, gif, png) en mi disco local.

no me importa el contenido del archivo (como en, no hago nada con él además de pasarlo a esta biblioteca para el método PUT). ¿Cómo puedo leer archivos de imagen y almacenarlos en std :: string? ¿y si el contenido del archivo contiene el terminador NULL?

intenté agregar algunos de los códigos que he probado, pero soy nuevo aquí y no estoy seguro de cómo pegar mi código aquí en el formato correcto. Cualquier ayuda sería apreciada.

+0

Para pegar el código de aquí, sólo sangra todo por 4 espacios. O pegue su código, selecciónelo, luego presione el botón que se ve así: '{}'. También puede colocar el código en línea con su texto rodeándolo con pequeñas cosillas. Creo que se llaman "back-ticks". En cada teclado que he usado, es la clave en la esquina superior izquierda, a la izquierda de la tecla 1. –

+0

@Benjamin: en el diseño del teclado alemán, está en la esquina superior derecha, a la izquierda de la tecla de retroceso. :) También necesitas presionar ctrl + alt para obtenerlo ... En cualquier caso, se entiende '\' '. – Xeo

+5

¿La biblioteca que utiliza realmente quiere datos binarios en una cadena? ¿Seguro que no es el nombre de archivo que quiere? Mientras que el tipo 'char' es un byte en casi todas las plataformas, usar' std :: string' para almacenar datos binarios me parece incorrecto. –

Respuesta

4

El método más fácil que se me ocurre. Abra el archivo en modo binario, luego lea todo en un stringstream.

std::ifstream fin("foo.png", std::ios::in | std::ios::binary); 
std::ostringstream oss; 
oss << fin.rdbuf(); 
std::string data(oss.str()); 
+0

esto es lo que hice exactamente. pero no funcionó ya que parecía haber cargado solo una porción de datos binarios. –

2
std::ifstream fin("foo.png", std::ios::binary); 
std::string data; 
data.reserve(1000000); 
std::copy(std::istreambuf_iterator<char>(fin), 
      std::istreambuf_iterator<char>(), 
      std::back_inserter(data)); 

Usted puede leer archivos de imagen a std::string con código como este. Ajuste el parámetro para el método reserve para que sea mayor que el 99% de los tamaños de sus archivos. Los bytes cero (que llama terminadores NULL) se tratan correctamente con ifstream y string.


he encontrado una buena article, donde se comparan varios métodos de carga del archivo binario. Aquí es el método más rápido de ese artículo:

std::ifstream fin("foo.png", std::ios::binary); 
fin.seekg(0, std::ios::end); 
std::string data; 
data.resize(fin.tellg()); 
fin.seekg(0, std::ios::beg); 
fin.read(&data[0], data.size()); 

Y aquí es la más corta:

std::ifstream fin("foo.png", std::ios::binary); 
std::string data((std::istreambuf_iterator<char>(fin)), 
       std::istreambuf_iterator<char>()); 

actualización

Algo como esto puede ser utilizado para alimentar a la devolución de llamada función (no la probé):

std::ifstream fin("foo.png", std::ios::binary); 
fin.seekg(0, std::ios::end); 
... 
curl_easy_setopt(m_ctx, CURLOPT_INFILESIZE, fin.tellg()); 
curl_easy_setopt(m_ctx, CURLOPT_READDATA,  (void *)&fin); 
fin.seekg(0, std::ios::beg); 
... 
static size_t put_callback(void *ptr, size_t size, size_t nmemb, void *data){ 
    std::ifstream* in = static_cast<std::ifstream*>(data); 
    if(in->eof()) return 0; 
    in->read((char *)ptr, size*nmemb); 
    return in->gcount(); 
} 
+0

He intentado la versión en corto en mi código ayer, pero esto tampoco funcionó. Trataré de obtener mi código aquí hoy para poder obtener más ayuda sobre esto. –

2

esta es la forma en la biblioteca hace llamadas puestas en 'datos' es cadena pasada como el contenido del archivo

stringstream data_stream.str(data.c_str()); 
curl_easy_setopt(m_ctx, CURLOPT_UPLOAD,  1L); 
curl_easy_setopt(m_ctx, CURLOPT_PUT,   1L); 
curl_easy_setopt(m_ctx, CURLOPT_INFILESIZE, data.length()); 
curl_easy_setopt(m_ctx, CURLOPT_READFUNCTION, put_callback); 
curl_easy_setopt(m_ctx, CURLOPT_READDATA,  (void *)&data_stream); 
curl_easy_setopt(m_ctx, CURLOPT_WRITEFUNCTION, get_callback); 
curl_easy_setopt(m_ctx, CURLOPT_WRITEDATA,  (void *)&m_request_response); 

y aquí está la frunction devolución de llamada para curlopt_readfunction

static size_t put_callback(void *ptr, size_t size, size_t nmemb, void *data){ 

    stringstream *output_stream; 
    int   retval; 

    output_stream = (stringstream *) data; 

    if(output_stream->eof()) return 0; 

    retval = min(size*nmemb,output_stream->str().size()); 
    output_stream->read((char *)ptr, retval); 

    //return the number of bytes processed 
    return retval; 
} 
+0

al menos de acuerdo con http://stackoverflow.com/questions/9612121/how-to-read-image-files-and-store-it-in-memorystdstring-in-c/9623954#9623954, la cadena debería ser capaz de almacenar cero bytes. hm. –

+0

Sí, la cadena puede almacenar cero bytes. El error está en la primera línea de tu código: 'data.c_str()'. Aquí la cadena terminada en cero se pasa como un puntero de char. Y entonces la cuerda se recorta con el primer byte cero. Elimine 'c_str()' innecesario, o use 'stringstream' del método de Benjamin en la devolución de llamada, o simplemente puede abrir' ifstream' y usarlo en la devolución de llamada (este enfoque proporciona un mejor rendimiento). –

+0

tienes razón. Supongo que necesito reescribir la función de devolución de llamada –

Cuestiones relacionadas