Leitura e gravação de arquivo binário

103

Estou tentando escrever um código para ler um arquivo binário em um buffer e, em seguida, gravar o buffer em outro arquivo. Eu tenho o seguinte código, mas o buffer armazena apenas alguns caracteres ASCII da primeira linha do arquivo e nada mais.

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
fonte
28
Você deve decidir usar o manuseio de arquivos iostream ou C. Por favor, não use ambos.
início de

Respostas:

172

Se você quiser fazer isso da maneira C ++, faça assim:

#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));
}

Se você precisar desses dados em um buffer para modificá-lo ou algo assim, faça o seguinte:

#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
fonte
4
E se eu quiser copiar apenas alguns segmentos de dados para o buffer. Como posso fazer isso? Digamos 1024 bytes.
como em
8
@Mikhail Aqui você pode encontrar alguns benchmarking.
Paolo M
3
AFAIK, arquivos binários às vezes contêm caracteres ilegíveis, na verdade, eles não são caracteres. Este código é seguro para leitura de arquivo base não textual? Meu conhecimento é curto nessa faixa :)
Andiana
5
assim chamado, charé usado em C / C ++ para armazenar bytes (e tem sido nos últimos 40 anos). é seguro fazer isso, contanto que você não tente realmente USAR esses dados como caracteres (não use strlen () nele, não imprima no console, etc). c ++ 17 apresenta std::bytepara este propósito (que ainda está char, charna verdade , disfarçado)
d.Candela
2
@DavidTran Não posso dizer sem saber mais - parece que você deve criar um exemplo mínimo que reproduza o problema e, em seguida, postar uma pergunta.
Björn Pollex
16

Aqui está um pequeno exemplo, a maneira de usar C ++ rdbuf. Peguei isso na web. Não consigo encontrar minha fonte original sobre este:

#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
fonte
8
O melhor método, não portátil, é permitir que o SO copie seu arquivo. Afinal, isso faz parte do que ela faz para viver; não há necessidade de reinventar a roda .
Thomas Matthews
@BarbaraKwarc: Atualizado de acordo com sua solicitação.
Thomas Matthews
14
 sizeof(buffer) == sizeof(char*) 

Em vez disso, use o comprimento.

Além disso, é melhor usar fopencom " wb" ....

Alexey Sudachen
fonte
Não é possível usar buffer.length()para buffer pode ter valores NULL dentro dele, anulando assim o propósito de strlen / length ().
John Greene
Melhor usar sizeof(buffer).
John Greene
8

sizeof (buffer) é o tamanho de um ponteiro na sua última linha NÃO o tamanho real do buffer. Você precisa usar o "comprimento" que você já estabeleceu em vez

jcoder
fonte
4

Você deve passar o comprimento para fwrite em vez de sizeof (buffer).

retrodrone
fonte
-1

Existe uma maneira muito mais simples. Isso não importa se é um arquivo binário ou de texto.

Use 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
fonte
-2

Isso pode ser feito com comandos simples no seguinte trecho.

Copia todo o arquivo de qualquer tamanho. Sem restrição de tamanho!

Apenas use isso. Testado e 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;
}

Ter um tamanho de buffer menor seria útil para copiar arquivos minúsculos. Até mesmo "char buffer [2]" faria o trabalho.

iMajetyHK
fonte
8
E se o tamanho do arquivo não for múltiplo do tamanho do buffer? Além disso, por que você deve declarar seu buffer como em int[]vez de char[]?
firegurafiku
Já mencionei que também funciona com char[]arquivos de qualquer tamanho, o que significa que não há condição de que o tamanho do arquivo seja um múltiplo do tamanho do buffer.
iMajetyHK
O fato de você ter dito que funciona não significa que funcione. O fato de que não funciona significa que não funciona.
nunojpg