UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2017 - January 2018

9.3.  Reading and writing disk files

In C, you can perform read/write operations in the following ways:

  • Read or write one character (or byte) at a time, with functions like fgetc and fputc.

  • Read or write one line of text (that is, one character line) at a time, with functions like fgets and fputs.

  • Read or write one block of characters (or bytes) at a time, with fread and fwrite.

In this course we are going to focus in the last way, block reading and writing, which is quite useful both for text and binary files.

9.3.1.  Reading/Writing one block at a time

The syntax for the fread function is:

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);

Here ptr is an array in which the data is stored. size indicates the size of each array element. n specifies the number of elements to read. stream is a file pointer that is associated with the opened file for reading. size_t is a type defined in the header file stdio.h. The fread function returns the number of elements that are actually read during the attempt or an EOF if it is the end of the file.

The fread function does not distinguish between end-of-file and another type of error so, if fread does not return the expected result, you must use feof and ferror functions to determine what exactly happened (we will see it in a moment).

The syntax for the fwrite function is:

#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);

ptr references the array that contains the data to be written to an opened file pointed to by the file pointer stream. size indicates the size of each element in the array. n specifies the number of elements to be written. The function returns the number of elements actually written; therefore, if no error has occurred, the value returned by fwrite should equal the third argument in the function. The return value may be less than the specified value if an error occurs.

As we have seen before, we have the feof function to determine when the end of a file is encountered.

#include <stdio.h>
int feof(FILE *stream);

This function returns 0 if the end of the file has not been reached; otherwise, it returns a nonzero integer.

Finally, we have the function ferror to know if there were a mistake in a read/write operation. It returns 0 if no error has occurred; otherwise, it returns a nonzero integer.

#include <stdio.h>
int ferror(FILE *stream);

The following program writes an array of numbers and then reads them one by one to calculate their sum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <stdio.h>
#define SIZE 6

int main(void)
{
  FILE *file;
  int numbers[SIZE] = {20, 20, 20, 20, 20, 20};
  char file_name[] = "numbers.bin";
  // This variable will store the result of writing/reading  
  size_t result;

  /* Opening the file for writing*/
  file = fopen(file_name, "w");
  if (file == NULL)
  {
	  printf("Error when opening file for writing.\n");
	  return -1;
  }
  // Writing a block of data
  result = fwrite(numbers, sizeof(int), SIZE, file);
  if (result!=SIZE)
  {
	  printf("The %d numbers have not been written.\n", SIZE);
  }

  if (fclose(file)!=0)
  {
    printf("Error when closing file.\n");
	return -1;
  }

  /* Open for reading */
  int sum = 0;
  file = fopen(file_name, "r");
  if (file == NULL)
  {
	  printf("Error when opening file for reading.\n");
	  return -1;
  }
  // Reading number by number, not in block.
  int num;
  while (!feof(file))
  {
    result = fread(&num, sizeof(int), 1, file);
	if (result != 1)
	{		
		break; 
	}
	sum = sum + num;
  }

  if (ferror(file)!=0)
  {
	  printf("An error has occurred while reading.\n");
  }
  else
  {
	  printf("The sum of numbers is: %d\n.",sum);
  }

  if (fclose(file)!=0)
  {
    printf("Error when closing file.\n");
	return -1;
  }
  return 0;
}
 

We know the array size and we can write the whole block of 6 integers. In case the number of elements were unknown, we would have to write one by one.

In line 47, break sentence is used to exit the reading loop, because an error or end of file has occurred and, as a consequence, no further operation is needed inside the loop. When exit the loop, the program checks what really has happened, in order to advise the user.