Leer y escribir archivos binarios

103

Estoy tratando de escribir código para leer un archivo binario en un búfer y luego escribir el búfer en otro archivo. Tengo el siguiente código, pero el búfer solo almacena un par de caracteres ASCII de la primera línea del archivo y nada más.

int length;
char * buffer;

ifstream is;
is.open ("C:\\Final.gif", ios::binary );
// get length of file:
is.seekg (0, ios::end);
length = is.tellg();
is.seekg (0, ios::beg);
// allocate memory:
buffer = new char [length];
// read data as a block:
is.read (buffer,length);
is.close();

FILE *pFile;
pFile = fopen ("C:\\myfile.gif", "w");
fwrite (buffer , 1 , sizeof(buffer) , pFile );
nf313743
fuente
28
Debería decidir utilizar el manejo de archivos iostream o C. No utilice ambos.
viernes

Respuestas:

172

Si desea hacer esto de la manera C ++, hágalo así:

#include <fstream>
#include <iterator>
#include <algorithm>

int main()
{
    std::ifstream input( "C:\\Final.gif", std::ios::binary );
    std::ofstream output( "C:\\myfile.gif", std::ios::binary );

    std::copy( 
        std::istreambuf_iterator<char>(input), 
        std::istreambuf_iterator<char>( ),
        std::ostreambuf_iterator<char>(output));
}

Si necesita esos datos en un búfer para modificarlos o algo así, haga esto:

#include <fstream>
#include <iterator>
#include <vector>

int main()
{
    std::ifstream input( "C:\\Final.gif", std::ios::binary );

    // copies all data into buffer
    std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(input), {});

}
Björn Pollex
fuente
4
¿Qué sucede si quiero copiar solo algún segmento de datos en el búfer? ¿Cómo puedo hacerlo? Digamos 1024 bytes.
likern
8
@Mikhail Aquí puede encontrar algunas evaluaciones comparativas.
Paolo M
3
AFAIK, los archivos binarios a veces contienen caracteres ilegibles, de hecho, no son caracteres en absoluto. ¿Es seguro este código para leer archivos base que no son de texto? Mi conocimiento es corto en este rango :)
Andiana
5
el llamado charse utiliza en C / C ++ para almacenar bytes (y lo ha sido durante los últimos 40 años). es seguro hacerlo, siempre y cuando no intente UTILIZAR esos datos como caracteres (no use strlen () en ellos, no los imprima en la consola, etc.). c ++ 17 se presenta std::bytepara este propósito (que todavía es char charen realidad disfrazado)
D. Candela
2
@DavidTran No puedo decir sin saber más; parece que debería crear un ejemplo mínimo que reproduzca el problema y luego publicar una pregunta.
Björn Pollex
16

Aquí hay un breve ejemplo, la forma en que C ++ usa rdbuf. Obtuve esto de la web. No puedo encontrar mi fuente original en esto:

#include <fstream>
#include <iostream>

int main () 
{
  std::ifstream f1 ("C:\\me.txt",std::fstream::binary);

  std::ofstream f2 ("C:\\me2.doc",std::fstream::trunc|std::fstream::binary);

  f2<<f1.rdbuf();

  return 0;
}
Thomas Matthews
fuente
8
El mejor método, no portátil, es dejar que el sistema operativo copie su archivo. Después de todo, eso es parte de lo que hace para ganarse la vida; no es necesario reinventar la rueda .
Thomas Matthews
@BarbaraKwarc: actualizado según su solicitud.
Thomas Matthews
14
 sizeof(buffer) == sizeof(char*) 

En su lugar, utilice la longitud.

Además, es mejor usarlo fopencon " wb" ....

Alexey Sudachen
fuente
No se puede usar buffer.length()para el búfer puede tener valores NULL dentro de él, lo que anula el propósito de strlen / length ().
John Greene
Mejor usar sizeof(buffer).
John Greene
8

sizeof (búfer) es el tamaño de un puntero en su última línea NO el tamaño real del búfer. En su lugar, debe usar la "longitud" que ya estableció

jcoder
fuente
4

Debe pasar longitud a fwrite en lugar de sizeof (búfer).

retrodrone
fuente
-1

Hay una forma mucho más sencilla. A esto no le importa si es un archivo binario o de texto.

Utilice noskipws.

char buf[SZ];
ifstream f("file");
int i;
for(i=0; f >> noskipws >> buffer[i]; i++);
ofstream f2("writeto");
for(int j=0; j < i; j++) f2 << noskipws << buffer[j];
Zeta
fuente
-2

Se puede hacer con comandos simples en el siguiente fragmento.

Copia el archivo completo de cualquier tamaño. ¡Sin restricciones de tamaño!

Solo usa esto. Probado y funcionando !!

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
  ifstream infile;
  infile.open("source.pdf",ios::binary|ios::in);

  ofstream outfile;
  outfile.open("temppdf.pdf",ios::binary|ios::out);

  int buffer[2];
  while(infile.read((char *)&buffer,sizeof(buffer)))
  {
      outfile.write((char *)&buffer,sizeof(buffer));
  }

  infile.close();
  outfile.close();
  return 0;
}

Tener un tamaño de búfer más pequeño sería útil para copiar archivos pequeños. Incluso "char buffer [2]" haría el trabajo.

iMajetyHK
fuente
8
¿Y si el tamaño del archivo no es múltiplo del tamaño del búfer? Además, ¿por qué tienes que declarar tu búfer como en int[]lugar de char[]?
firegurafiku
Ya mencioné que también funciona con char[]archivos de cualquier tamaño, lo que significa que no hay condición de que el tamaño del archivo sea un múltiplo del tamaño del búfer.
iMajetyHK
El hecho de que hayas dicho que funciona no significa que funcione. El hecho de que no funcione significa que no funciona.
nunojpg