Writing to Binary Files

At the very beginning of this chapter, the two file types were mentioned: plain text (formally called ASCII) and binary. All of the previous examples have used plain-text files, which are human readable, but you can also write to and read from binary files using C. The basic ideas for working with binary files are the same, but the specific functions are different.

Binary files are opened and closed like ASCII files, except that you should use the b modifier on the mode:

FILE *fp;
fp = fopen ("thefile", "wb");
// Write to the file.
fclose(fp);

Once you've successfully opened the file, you can write data to it using fwrite(). Its syntax is more complex than you've seen so far:

fwrite (write_data_pointer,
					
					bytes_to_write, blocks, fp);

The first argument to fwrite() is a pointer to the address of the data being written. This can be an actual pointer (like to a string or a number) or an array (which, as you've seen, has pointer-like qualities). The second argument indicates the size, in bytes, of each block of data. The third argument represents the number of blocks being written. For example, you might write one block, which is a number, or one hundred blocks, which are the elements of an array. The final argument is the file pointer.

In this next example, an array of 50 random numbers will be generated (see the sidebar) and then written to a binary file. Subsequent examples will read the entire file and grab random values from it.

Generating Random Numbers

This application requires the generation of 50 random numbers. However, computers aren't very good at doing things randomly—given the same set of instructions, they should produce the same results—so to reliably create random numbers requires a few lines of code that will be new to you.

The C stdlib.h file contains the definition for the rand() function, which returns a random number between 0 and 32,767. While multiple calls to this function within an application will return different numbers, each time you run the application, it will most likely return the same set of random numbers. To compensate for this, the srand() function is first called to seed the process. The standard code for using srand() is

srand((unsigned)time(NULL));

Basically this line feeds srand() one argument, using the time() function to generate that argument. The time() function, found in the time.h library file, returns the number of seconds since midnight on January 1, 1970. Thus, every time the application is run, srand() is fed a different value, as time() returns an increasingly larger number of seconds.

Lastly, this application wants to limit the range of random numbers to be less than 100. The easiest way to accomplish this is to use the remainder of dividing a random number by 100. So if a random number is 32,767, the remainder of dividing that by 100 would be 67. If the number is 22,584, its modulus would be 84.

In the end, the key to this exercise is to learn how to write binary data to a file. The actual generation of random numbers within a particular range is just a secondary requirement. Do not be too confused or concerned with the particulars of that syntax.


To write to a binary file

1.
Create a new file or project in your text editor or IDE.

2.
Type the standard beginning lines of code (Script 12.5):

/* binary_write.c - Script 12.5 */
#include <stdio.h>

Script 12.5. This program writes fifty random numbers (between 0 and 99) to a binary file.


3.
Require two more standard libraries:

#include <stdlib.h>
#include <time.h>

The first library makes the rand() and srand() functions available to this application. The second makes the time() function available, which will be needed with srand(). See the sidebar for more.

4.
Set the file path and name as a C preprocessor macro:

#define THEFILE
 "/Users/larry/Desktop/numbers.dat"

or

#define THEFILE "C:\Documents and
 Settings\Larry Ullman\Desktop\
 numbers.dat"

Because the file will store binary data, not plain text, you don't want to use the .txt extension. You can either omit the extension entirely or use .dat (a three-letter extension representing data).

5.
Create a constant macro representing the number of items in the array:

#define ITEMS 50

How many items are stored in the array will be a relevant number many times over in this application, so it makes sense to set it as a preprocessor macro.

6.
Begin the main function and create a file pointer:

int main (void) {
FILE *fp;

7.
Define the required variables:

int i;
int numbers[ITEMS];

The i variable will be a loop counter; numbers is the array in which random numbers will be stored.

8.
Open the file for binary writing:

fp = fopen(THEFILE, "wb");

This call opens the file for writing, creating the file if it doesn't exist, and wiping out any existing data. The binary mode is indicated by adding the b. This is only required on Windows but is still a good idea on all operating systems.

9.
Start a conditional based on the file pointer:

if (fp != NULL) {

10.
Seed the rand() function:

srand((unsigned)time(NULL));

This line is required to generate truly random numbers. See the sidebar for a more detailed explanation of the purpose and syntax.

11.
Populate the array with random numbers:

for (i = 0; i < ITEMS; i++) {
    numbers[i] = rand() % 100;
}

The for loop counts from i to ITEMS, the number of elements in the array. Within the loop, each element is assigned a random value between 0 and 99. This limit is accomplished by assigning the remainder of dividing the random number by 100, rather than assigning the random number itself (which could be as high as 32,767).

12.
Write the array elements to the binary file and print a message to the user:

fwrite (numbers, sizeof(int), ITEMS,
 fp);
printf ("The data has been
 written.
");

The fwrite() line starts by using the numbers variable as its pointer. This works because an array name is equivalent to its address in C (see Chapter 9, “Working with Pointers”). The function is then told to write ITEMS number of blocks, each of which is sizeof(int) bytes in size. We use sizeof(int) because numbers is an array of integers.

In layman's terms, the fwrite() line could be described as: go to the memory block, which starts where the numbers array starts, then take the next 50 blocks of data (each block being 4 bytes—the common size of an integer—in length) and write these to the file referenced by fp.

The printf() line just gives you something to see when the application runs. You could also print out all of the randomly generated numbers, if you want.

13.
Complete the fp conditional:

} else {
    printf ("The file could not
 be opened.
");
    return 1;
}

14.
Close the file:

if (fclose(fp) != 0) {

    printf ("The file could not
 be closed.
");
}

15.
Complete the main function:

    getchar();
    return 0;
}

16.
Save the file as binary_write.c, compile, and debug as necessary.

17.
Run the application (Figure 12.10).

Figure 12.10. The results of successfully writing 50 random numbers to a binary data file.


18.
Open numbers.dat in a text editor (Figure 12.11).

Figure 12.11. The illegible binary contents of the numbers.dat file.


✓ Tips

  • Whereas the fprintf() function writes text to a text file, the fwrite() function copies data stored in memory—which is always binary—to a file. This is why the first argument is a pointer (the address of a memory block), not a simple variable.

  • If you inadvertently open an ASCII file as binary on Windows, C will not handle the line endings properly, meaning you'll need to cope with them in your C code.

  • In case you were curious, ASCII stands for American Standard Code for Information Interchange.

  • Instead of using a loop to populate the array and then writing the entire array to the file, this application could write the random number directly to the binary file inside of the loop. In such a case you would change your fwrite() line so that it writes a single block of sizeof(int) size to the file at a time, rather than ITEMS number of blocks of sizeof(int) data. In other words, instead of creating an array of, say, 50 elements and then writing 50 blocks of data in one fwrite() call, you would just write a single block of data 50 times.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset