Node:Block input and output, Next:, Previous:Closing a file, Up:High-level file routines



Block input and output

You can use the two functions in this section, fread and fwrite, to read and write text in blocks of fixed size, rather than by line or character. You can also use these two functions to read and write blocks of binary data. This feature is useful if you want to read and write data in the same format used by your program. For example, you can store an entire multidimensional array of floating-point variables in a file with the fwrite command, then read it back in directly later with the fread command, without any loss of precision caused by converting the floats to strings for use with the fprintf function, for example. (The main drawback to using binary files rather than formatted ASCII text files is that you cannot easily read and edit the files you create with a text editor.)

For example, to write an array called my_array, containing object_count data objects (such as integers), each of size object_size, to the stream my_stream, you might use the following line of code:

fwrite (&my_array, object_size, object_count, my_stream);

To read my_array back from my_stream, you might then use the following line:

fread (&my_array, object_size, object_count, my_stream);

Here is a short table to help you remember the directions in which fwrite and fread work.

fwrite
from an array, to a file
fread
from a file, to an array

The fwrite function takes four parameters. The first parameter to fwrite is a void pointer (void *) to an array that contains the data that will be written to the file. The second parameter is a variable of type size_t specifying the size of each object to be written, and the third parameter, also of type size_t, specifies the number of those objects that are to be written. The final parameter is the stream to be written to (type FILE *). If the value returned by fopen does not match the third parameter passed (that is, the number of objects to be written), then there was an error.

Like fwrite, the fread function takes four parameters. Its first parameter is a void pointer to the array that will be written to. Its second parameter, of type size_t, specifies how large each object to be read is, and its third parameter, of type size_t, specifies how many of each object is to be read. The last parameter is simply the stream to read from. Again, if the return value of this function does not match the third parameter, which specifies how many object were to be read, there was an error.

Here is an example that creates an array and fills it with multiples of 2, prints it out, writes the array's data to a file with fwrite, zeroes the array and prints it out, reads the data from the file back into the array with fread, then prints the array out again so you can compare its data with the first set of data.

#include <stdio.h>

int main()
{
  int row, column;
  FILE *my_stream;
  int close_error;
  char my_filename[] = "my_numbers.dat";
  size_t object_size = sizeof(int);
  size_t object_count = 25;
  size_t op_return;

  int my_array[5][5] =
  {
    2,  4,  6,  8, 10,
    12, 14, 16, 18, 20,
    22, 24, 26, 28, 30,
    32, 34, 36, 38, 40,
    42, 44, 46, 48, 50
  };
  printf ("Initial values of array:\n");
  for (row = 0; row <= 4; row++)
    {
      for (column = 0; column <=4; column++)
	{
	  printf ("%d  ", my_array[row][column]);
	}
      printf ("\n");
    }

  my_stream = fopen (my_filename, "w");
  op_return = fwrite (&my_array, object_size, object_count, my_stream);
  if (op_return != object_count)
    {
      printf ("Error writing data to file.\n");
    }
  else
    {
      printf ("Successfully wrote data to file.\n");
    }

  /* Close stream; skip error-checking for brevity of example */
  fclose (my_stream);

  printf ("Zeroing array...\n");
  for (row = 0; row <= 4; row++)
    {
      for (column = 0; column <=4; column++)
	{
	  my_array[row][column] = 0;
	  printf ("%d  ", my_array[row][column]);
	}
      printf ("\n");
    }

  printf ("Now reading data back in...\n");
  my_stream = fopen (my_filename, "r");
  op_return = fread (&my_array, object_size, object_count, my_stream);
  if (op_return != object_count)
    {
      printf ("Error reading data from file.\n");
    }
  else
    {
      printf ("Successfully read data from file.\n");
    }
  for (row = 0; row <= 4; row++)
    {
      for (column = 0; column <=4; column++)
	{
	  printf ("%d  ", my_array[row][column]);
	}
      printf ("\n");
    }

  /* Close stream; skip error-checking for brevity of example */
  fclose (my_stream);

  return 0;
}

If all goes well, the code example above will produce the following output:

Initial values of array:
2  4  6  8  10
12  14  16  18  20
22  24  26  28  30
32  34  36  38  40
42  44  46  48  50
Successfully wrote data to file.
Zeroing array...
0  0  0  0  0
0  0  0  0  0
0  0  0  0  0
0  0  0  0  0
0  0  0  0  0
Now reading data back in...
Successfully read data from file.
2  4  6  8  10
12  14  16  18  20
22  24  26  28  30
32  34  36  38  40
42  44  46  48  50

If you attempt to view the file my_numbers.dat produced by the program above with a GNU command such as more numbers.dat, you will see only garbage, because the information is stored in binary format, not readable by humans. After attempting to view this binary file, your terminal may continue to show only garbage and you may have to reset it. You may be able to do this with a menu option (if you are running gnome-terminal, for example), or you may have to type reset blindly.