158

I'm trying to write code to read a binary file into a buffer, then write the buffer to another file. I have the following code, but the buffer only stores a couple of ASCII characters from the first line in the file and nothing else.

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 );
4
  • 39
    You should decide to use iostream or C file handling. Please do not use both. Commented Mar 24, 2011 at 14:03
  • 3
    There is a mistake in the above code regarding the buffer variable. It's type should be unsigned char and the allocation should be buffer = new unsigned char[length + 1] and then buffer[length] = '\0'. I know that the question was posted many years ago, but nobody has written about this. Commented Mar 28, 2022 at 5:10
  • 1
    @RalucaPandaru, given the input file is a GIF and explicitly read as ios::binary, adding a zero-terminator as you suggested makes no sense. Also difference between using a char or unsigned char does not make much difference here, as the code is not trying to interpret the file content. What is wrong with the above code is the sizeof(buffer) is 4 or 8 (32/64-bit pointer). So it always writes 4/8 bytes into the output file. Author should use length instead of sizeof(buffer). Commented Jul 18, 2023 at 9:37
  • In the final step, sizeof(buffer) is the size of a pointer to characters. That will be the same whether you have allocated the memory or not. In this case, the variable length has the quantity you need to pass to fread so just use that. Commented Sep 4, 2024 at 16:55

8 Answers 8

253

If you want to do this the C++ way, do it like this:

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

If you need that data in a buffer to modify it or something, do this:

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

}
Sign up to request clarification or add additional context in comments.

10 Comments

What if I want copy only some segment of data to buffer. How I can do it? Let say 1024 bytes.
@Mikhail Here you can find some benchmarking.
AFAIK, binary files sometimes contain unreadable char, in the fact, they are not char at all. Is this code safe for reading non-text base file? My knowledge is short in this range :)
so-called char is used in C/C++ to store bytes (and have been for the last 40 years). it's safe to do so, as long as you don't try to actually USE that data as characters (don't use strlen() on it, don't print it to console, etc). c++17 introduces std::byte for this purpose (which is still char actually char in disguise)
@DavidTran Can't say without knowing more - this seems like you should create a minimal example that reproduces the issue, and then post a question.
|
18

Here is a short example, the C++ way using rdbuf. I got this from the web. I can't find my original source on this:

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

1 Comment

The best, non portable, method is to let the OS copy your file. After all, that is part of what it does for a living; no need to reinvent the wheel.
15
 sizeof(buffer) == sizeof(char*) 

Use length instead.

Also, better to use fopen with "wb"....

2 Comments

Can't use buffer.length() for buffer may have NULL values inside it thereby defeating the purpose of strlen/length().
Better to use sizeof(buffer).
10

sizeof(buffer) is the size of a pointer on your last line NOT the actual size of the buffer. You need to use "length" that you already established instead

Comments

6

You should pass length into fwrite instead of sizeof(buffer).

Comments

5

Here is implementation of standard C++ 14 using vectors and tuples to Read and Write Text, Binary and Hex files.

Snippet code :

try {
    if (file_type == BINARY_FILE) {

        /*Open the stream in binary mode.*/
        std::ifstream bin_file(file_name, std::ios::binary);

        if (bin_file.good()) {
            /*Read Binary data using streambuffer iterators.*/
            std::vector<uint8_t> v_buf((std::istreambuf_iterator<char>(bin_file)), (std::istreambuf_iterator<char>()));
            vec_buf = v_buf;
            bin_file.close();
        }

        else {
            throw std::exception();
        }

    }

    else if (file_type == ASCII_FILE) {

        /*Open the stream in default mode.*/
        std::ifstream ascii_file(file_name);
        string ascii_data;

        if (ascii_file.good()) {
            /*Read ASCII data using getline*/
            while (getline(ascii_file, ascii_data))
                str_buf += ascii_data + "\n";

            ascii_file.close();
        }
        else {
            throw std::exception();
        }
    }

    else if (file_type == HEX_FILE) {

        /*Open the stream in default mode.*/
        std::ifstream hex_file(file_name);

        if (hex_file.good()) {
            /*Read Hex data using streambuffer iterators.*/
            std::vector<char> h_buf((std::istreambuf_iterator<char>(hex_file)), (std::istreambuf_iterator<char>()));
            string hex_str_buf(h_buf.begin(), h_buf.end());
            hex_buf = hex_str_buf;

            hex_file.close();
        }
        else {
            throw std::exception();
        }
    }

}

Full Source code can be found here

Comments

0

It can be done with simple commands in the following snippet.

Copies the whole file of any size. No size constraint!

Just use this. Tested And Working!!

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

Having a smaller buffer size would be helpful in copying tiny files. Even "char buffer[2]" would do the job.

4 Comments

And what if file size isn't multiple of buffer size? Moreover, why do you have to declare your buffer as int[] instead of char[]?
I already mentioned it works with char[] too and files of any size which means there's no condition that file size should be a multiple of buffer size.
The fact that you said it works does not mean it works. The fact that it does not work means it does not work.
The least you could do is to change 'int buffer[2]' to 'char buffer[1]' to make things work without changing the code to fix bugs.
-1

There is a much simpler way. This does not care if it is binary or text file.

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];

Or you can just use string instead of the buffer.

string s; char c;
ifstream f("image.jpg");
while(f >> noskipws >> c) s += c;
ofstream f2("copy.jpg");
f2 << s;

normally stream skips white space characters like space or new line, tab and all other control characters. But noskipws makes all the characters transferred. So this will not only copy a text file but also a binary file. And stream uses buffer internally, I assume the speed won't be slow.

1 Comment

You might want to elaborate on this to make it more understandable

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.