14.6. mycopy.cpp: A File Processing Example

Making a copy of a file is a simple but essential file operation supported by most systems. Furthermore, the copy operation should support both text and binary files. (Text files are a special subclass of binary files, so the copy operation will work with text files even when opened in binary mode.) Three of the four I/O operations described previously support binary I/O, but line-oriented I/O operations only make sense with character-oriented I/O. Therefore, the following program demonstrates how to copy a file using character, block, and buffer I/O operations, but not line operations.

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
	string	input;						// (a)
	cout << "Please enter the source file: ";
	getline(cin, input);

	ifstream	in(input, ios::binary);			// (b)

	if(!in.good())						// (c)
	{
		cerr << "Unable to open " << input << endl;
		exit(1);
	}

	string	output;						// (d)
	cout << "Please enter the destination file: ";
	getline(cin, output);

	ofstream	out(output, ios::binary);		// (e)

	if(!out.good())						// (f)
	{
		cerr << "Unable to open " << output << endl;
		exit(1);
	}

	// file copy code goes here

	return 0;
}
mycopy.cpp: opening the files. The first, and largest, part of the program involves opening the files and testing to insure that they opened successfully. To save space and time, this part of the program is presented only once.
  1. Prompt for and read the name of the input file
  2. Open the input file in binary mode
  3. Test the input stream object to make sure the file opened
  4. Prompt for and read the name of the output file
  5. Open the output file in binary mode
  6. Test the output stream object to make sure the file opened

Character I/O

char	c;				// (a)
while (in.get(c))			// (b)
	out.put(c);			// (c)
int	c;				// (d)
while ((c = in.get()) != EOF)		// (e)
	out.put(c);			// (f)
mycopy.cpp: character copy. C++ has many character I/O functions. The following code fragments illustrate just three of the available functions. The next section will provide greater detail explaining why these functions work with binary data.
  1. The function reads data one character or one byte at a time
  2. The full prototype for the get function is istream& get(char& c);. So, we can see that the parameter is passed by reference, which is how the character read from the file is returned. The stream classes define a conversion or casting operator, operator bool(), that converts the returned istream& into a Boolean value that can control the loop.
  3. The character is simply copied to the output file.
  4. This overloaded version of the get function returns each character as an integer, which is necessary for the next step.
  5. The get function returns all characters as non-negative (i.e., ≥ 0) integers. The character is first stored in the variable c and then compared to the symbolic constant EOF, which is typically -1. The get function returns EOF when it reaches the end of the file.
  6. C++ converts back and forth between characters and integers without an explicit type cast, which allows the put function, whose parameter type is char, to copy the character to the output file.

Block I/O

char	block[512];					// (a)
int	count;						// (b)

in.read(block, 512);					// (c)
while ((count = in.gcount()) > 0)			// (d)
{
	out.write(block, count);			// (e)
	in.read(block, 512);				// (f)
}
mycopy.cpp: block copy. The block I/O operations read and write data as blocks of bytes without interpreting what the bytes mean. C++ does not have a data type called "byte," the char type is used. A block's size is arbitrary but usually the size of the data being processed - for example, the size of a structure. The copy program processes the contents of a file without regard to any data boundaries that might exist, so we set a block size that works well with most hardware.
  1. Defines a read/write buffer for the block I/O functions. Note that this buffer is not the filebuf aggregated with the stream objects.
  2. The count variables stores the number of bytes read from the file.
  3. The first read operation takes place outside the loop. The read function requires two parameters: The first parameter is that address of the buffer where the data read from the file is stored. Recall that all arrays are passed by pointer, so the read function will store the data in the block array. The second parameter is the number of bytes to read from the file. The first read function call appears outside and above the loop to prepare for calling the gcount function.
  4. The gcount function returns the number of bytes read by the last read or get operation. The number of bytes is stored in the count variable, and the loop continues as long as at least one byte was read.
  5. The write function also requires two parameters: The first parameter is the address where the data is stored in main memory; the second parameter is the number of bytes to write to the file. We use the variable count here rather then the constant value of 512 because the last block read may be partially filled (i.e., it may contain less than 512 bytes). The read function writes count bytes beginning at block to the output file.
  6. The second read function call appears inside and at the bottom of the loop. The behavior of the read is as described for step 3 above. The number of bytes read by this function call is processed by the gcount function, which drives the loop until all data is copied.

Buffer I/O

	out << in.rdbuf();					// (a) & (b)
mycopy.cpp: buffer copy. Unlike the block copy outlined above, buffer copy does utilize the filebuf object (Figure 2) that is aggregated to each stream object. The technique illustrated here is generally not useful for most file processing tasks, but it is very compact and efficient for the specialized task illustrated here.
  1. The rdbuf function returns a pointer to the filebuf object aggregated to the in stream object.
  2. The overloaded inserter function, operator<<, provides the looping needed to copy the entire contents of the input file to the output file.

Downloadable File

mycopy.cpp