usar txt pasar operaciones leer guardarlo guardar datos con como binarios binario arreglo archivos archivo c++ file-io vector binaryfiles

c++ - txt - Cómo leer un archivo binario en un vector de caracteres sin signo



operaciones con archivos binarios en c (4)

Al probar el rendimiento, incluiría un caso de prueba para:

std::vector<BYTE> readFile(const char* filename) { // open the file: std::ifstream file(filename, std::ios::binary); // Stop eating new lines in binary mode!!! file.unsetf(std::ios::skipws); // get its size: std::streampos fileSize; file.seekg(0, std::ios::end); fileSize = file.tellg(); file.seekg(0, std::ios::beg); // reserve capacity std::vector<BYTE> vec; vec.reserve(fileSize); // read the data: vec.insert(vec.begin(), std::istream_iterator<BYTE>(file), std::istream_iterator<BYTE>()); return vec; }

Mi pensamiento es que el constructor del Método 1 toca los elementos en el vector , y luego la read toca cada elemento nuevamente.

El Método 2 y el Método 3 parecen más prometedores, pero podrían sufrir uno o más resize de resize . De ahí la razón para reserve antes de leer o insertar.

También probaría con std::copy :

... std::vector<byte> vec; vec.reserve(fileSize); std::copy(std::istream_iterator<BYTE>(file), std::istream_iterator<BYTE>(), std::back_inserter(vec));

Al final, creo que la mejor solución evitará el operator >> de istream_iterator (y todos los gastos generales y la bondad del operator >> tratando de interpretar los datos binarios). Pero no sé qué usar que te permite copiar directamente los datos en el vector.

Finalmente, mi prueba con datos binarios muestra que ios::binary no se está respetando. De ahí el motivo de noskipws de <iomanip> .

Últimamente me pidieron que escribiera una función que lea el archivo binario en std::vector<BYTE> donde BYTE es un unsigned char . Rápidamente vine con algo como esto:

#include <fstream> #include <vector> typedef unsigned char BYTE; std::vector<BYTE> readFile(const char* filename) { // open the file: std::streampos fileSize; std::ifstream file(filename, std::ios::binary); // get its size: file.seekg(0, std::ios::end); fileSize = file.tellg(); file.seekg(0, std::ios::beg); // read the data: std::vector<BYTE> fileData(fileSize); file.read((char*) &fileData[0], fileSize); return fileData; }

que parece ser innecesariamente complicado y el molde explícito en char* que me vi obligado a utilizar al llamar a file.read no me hace sentir mejor al respecto.

Otra opción es usar std::istreambuf_iterator :

std::vector<BYTE> readFile(const char* filename) { // open the file: std::ifstream file(filename, std::ios::binary); // read the data: return std::vector<BYTE>((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); }

que es bastante simple y corto, pero aún tengo que usar std::istreambuf_iterator<char> incluso cuando estoy leyendo en std::vector<unsigned char> .

La última opción que parece ser perfectamente sencilla es usar std::basic_ifstream<BYTE> , que expresa un poco explícitamente que "Quiero un flujo de archivos de entrada y quiero usarlo para leer BYTE s" :

std::vector<BYTE> readFile(const char* filename) { // open the file: std::basic_ifstream<BYTE> file(filename, std::ios::binary); // read the data: return std::vector<BYTE>((std::istreambuf_iterator<BYTE>(file)), std::istreambuf_iterator<BYTE>()); }

pero no estoy seguro si std::basic_ifstream<BYTE> es una elección apropiada en este caso.

¿Cuál es la mejor manera de leer un archivo binario en el vector ? También me gustaría saber qué está sucediendo "detrás de la escena" y cuáles son los posibles problemas que podría encontrar (aparte de que la transmisión no se abra correctamente, lo que podría evitarse con la simple comprobación de is_open ).

¿Hay alguna buena razón por la cual uno preferiría usar std::istreambuf_iterator aquí?
(La única ventaja que puedo ver es la simplicidad)


Como está cargando todo el archivo en la memoria, la versión más óptima es asignar el archivo a la memoria. Esto se debe a que el kernel carga el archivo en la memoria caché de la página del kernel de todos modos y al mapear el archivo solo expone esas páginas en la caché en su proceso. También conocido como copia cero.

Cuando utiliza std::vector<> , copia los datos de la memoria caché de la página del kernel en std::vector<> que no es necesario cuando solo quiere leer el archivo.

Además, al pasar dos iteradores de entrada a std::vector<> crece su búfer mientras lee porque no conoce el tamaño del archivo. Al redimensionar std::vector<> al tamaño del archivo primero, innecesariamente pone a cero su contenido porque de todos modos se sobrescribirá con datos de archivo. Ambos métodos son subóptimos en términos de espacio y tiempo.


Hubiera pensado que el primer método, usar el tamaño y usar stream::read() sería el más eficiente. El "costo" de la conversión a char * es muy probable que los cambios en cero de este tipo simplemente le digan al compilador que "Oye, sé que piensas que es un tipo diferente, pero realmente quiero este tipo aquí ...", y no agregue instrucciones adicionales; si desea confirmar esto, intente leer el archivo en una matriz char y compare el código ensamblador real. Aparte de un poco de trabajo adicional para averiguar la dirección del búfer dentro del vector, no debería haber ninguna diferencia.

Como siempre, la única forma de saber con certeza EN SU CASO cuál es el más eficiente es medirlo. "Preguntar en Internet" no es una prueba.


std::ifstream stream("mona-lisa.raw", std::ios::in | std::ios::binary); std::vector<uint8_t> contents((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>()); for(auto i: contents) { int value = i; std::cout << "data: " << value << std::endl; } std::cout << "file size: " << contents.size() << std::endl;