Example: A Simple Sequential File Copy
The following sections show short example programs implementing a simple sequential file copy program in three different ways:
- Using the Standard C library
- Using Windows
- Using a single Windows convenience function, CopyFile
File Copying with the Standard C Library
As illustrated in Program 1-1, the Standard C library supports stream FILE I/O objects that are similar to, although not as general as, the Windows HANDLE objects shown in Program 1-2.
Program 1-1. cpC: File Copying with the C Library
This simple example clearly illustrates some common programming assumptions and conventions that do not always apply with Windows.
/* Chapter 1. Basic cp file copy program.
C library Implementation. */
/* cp file1 file2: Copy file1 to file2. */
#include <stdio.h>
#include <errno.h>
#define BUF_SIZE 256
int main (int argc, char *argv [])
{
FILE *in_file, *out_file;
char rec [BUF_SIZE];
size_t bytes_in, bytes_out;
if (argc != 3) {
printf ("Usage: cpC file1 file2\n");
return 1;
}
in_file = fopen (argv [1], "rb");
if (in_file == NULL) {
perror (argv [1]);
return 2;
}
out_file = fopen (argv [2], "wb");
if (out_file == NULL) {
perror (argv [2]);
return 3;
}
/* Process the input file a record at a time. */
while ((bytes_in = fread (rec, 1, BUF_SIZE, in_file)) > 0) {
bytes_out = fwrite (rec, 1, bytes_in, out_file);
if (bytes_out != bytes_in) {
perror ("Fatal write error.");
return 4;
}
}
fclose (in_file);
fclose (out_file);
return 0;
}
- Open file objects are identified by pointers to FILE structures (UNIX uses integer file descriptors). NULL indicates an invalid value. The pointers are, in effect, a form of handle to the open file object.
- The call to fopen specifies whether the file is to be treated as a text file or a binary file. Text files contain system-specific character sequences to indicate situations such as an end of line. On many systems, including Windows, I/O operations on a text file convert between the end-of-line character sequence and the null character that C interprets as the end of a string. In the example, both files are opened in binary mode.
- Errors are diagnosed with perror, which, in turn, accesses the global variable errno to obtain information about the function call failure. Alternatively, the ferror function could be used to return an error code that is associated with the FILE rather than the system.Appendix C, C library performance for sequential I/O is competitive with alternative implementations. Nonetheless, programs are still constrained to synchronous I/O operations, although this constraint will be lifted somewhat when using Windows threads (starting in Chapter 7).C library file processing programs, like their UNIX equivalents, are able to perform random access file operations (using fseek or, in the case of text files, fsetpos and fgetpos), but that is the limit of sophistication of Standard C library file I/O. Note: Visual C++ does provide nonstandard extensions that support, for example, file locking. Finally, the C library cannot control file security.In summary, if simple synchronous file or console I/O is all that is needed, then use the C library to write portable programs that will run under Windows.
File Copying with Windows
Program 1-2 shows the same program using the Windows API, and the same basic techniques, style, and conventions will be used throughout this book.Program 1-2. cpW: File Copying with Windows, First Implementation
This simple example illustrates some Windows programming features that Chapter 2 will start to explain in detail.
/* Chapter 1. Basic cp file copy program.
Windows Implementation. */
/* cpW file1 file2: Copy file1 to file2. */
#include <windows.h>
#include <stdio.h>
#define BUF_SIZE 256
int main (int argc, LPTSTR argv [])
{
HANDLE hIn, hOut;
DWORD nIn, nOut;
CHAR Buffer [BUF_SIZE];
if (argc != 3) {
printf ("Usage: cpW file1 file2\n");
return 1;
}
hIn = CreateFile (argv [1], GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (hIn == INVALID_HANDLE_VALUE) {
printf ("Cannot open input file. Error: %x\n",
GetLastError ());
return 2;
}
hOut = CreateFile (argv [2], GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOut == INVALID_HANDLE_VALUE) {
printf ("Cannot open output file. Error: %x\n",
GetLastError ());
return 3;
}
while (ReadFile (hIn, Buffer, BUF_SIZE, &nIn, NULL) && nIn > 0) {
WriteFile (hOut, Buffer, nIn, &nOut, NULL);
if (nIn != nOut) {
printf ("Fatal write error: %x\n", GetLastError ());
return 4;
}
}
CloseHandle (hIn);
CloseHandle (hOut);
return 0;
}- <windows.h> is always included and contains all Windows function definitions and data types.Appendix A shows how to exclude unwanted definitions to expedite compilations and save disk space.
- All Windows objects are identified by variables of type HANDLE, and a single generic CloseHandle function applies to most objects.Program 2-2 shows how to obtain Windows-generated textual error messages.Chapter 15. The output file in this example is not secured.
- Functions such as CreateFile have a rich set of options, and the example uses default values.
File Copying with a Windows Convenience Function
Windows has a number of convenience functions that combine several functions to perform a common task. These convenience functions can also improve performance in some cases (see Appendix C). CopyFile, for example, greatly simplifies the file copy program (Program 1-3). Among other things, there is no need to be concerned with the appropriate buffer size, which was arbitrarily set to 256 in the two preceding programs.Program 1-3. cpCF: File Copying with a Windows Convenience Function
/* Chapter 1. Basic cp file copy program. Windows implementation
using CopyFile for convenience and improved performance. */
/* cpCF file1 file2: Copy file1 to file2. */
#include <windows.h>
#include <stdio.h>
int main (int argc, LPTSTR argv [])
{
if (argc != 3) {
printf ("Usage: cpCF file1 file2\n");
return 1;
}
if (!CopyFile (argv [1], argv [2], FALSE)) {
printf ("CopyFile Error: %x\n", GetLastError ());
return 2;
}
return 0;
}