Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit


Computing for Engineers

Lecture 7

Files


1. Files – the basics

We have already seen lots of examples of inputting and outputting data. The assumption thus far has been that data is inputted from a keyboard and         outputted to a monitor.

However in general large amounts of information need to be input or output     from files. A file is just a place where information is stored and can be accessed by a computer. In C, we have seen that the standard i/o library has functions scanf() and printf() for inputting and outputting information. It also has a            number of functions, many of which we will look at in this lecture, for                  accessing information from files.

It should be noted here that in the above paragraph, a distinction is implied between inputting and outputting from keyboard/monitor and

inputting/outputting from/to file. In C there is no such distinction. Instead        there is the concept of an i/o stream which for example, can be a sequence of characters. The stream is associated with either a device (such as a monitor or a keyboard) or a file. When a C program started, 3 text streams are opened      automatically. They are the standard input for reading input, standard output for writing output and standard error for writing diagnostic output. Normally   the standard input stream is associated with the keyboard device and the         standard output and error streams are associated with the monitor device.      However, they can easily be re-associated with a file.

When talking about files, a distinction is made between a text file and a binary file. A text file is a stream of characters so that the binary representation of the data in the file is the ASCII representation of each character. On the other           hand, a binary file is just a stream of bytes with each byte having no special        significance as a character and is identical to the internal representation of the  data.

Thus, if an integer value of 100000 is stored in a text file, this would take 6 bytes corresponding to 6 characters (digits), each represented in ASCII.

However, as a binary file, it would only require 4 bytes (if it was stored as an int variable).

An important factor to remember when creating files is portability. This means that the data within a file is readable on all kinds of computers and operating    systems.

1.1.     Files – text and binary files - summary

A file is a place where information is stored and can be accessed by a computer.

A file can store numerical or textual data.

A text file stores all of the data as “ASCII” characters and then stores the binary representation of each ASCII character.

A binary file stores numerical data in its binary form (for example the integer 10 is stored as the 4-byte representation of 10).

200    37    50

Binary file

‘2’ ‘0’ ‘0’ ‘3’ ‘7’ ‘5’ ‘0’

1.2.     Important differences between text and binary files

Text files are larger than binary files (when holding the same amount of data).

Text files are known as “human-readable” – they can be examined via            “Notepad++” or any other text editor. (NB – “Notepad” on Windows cannot read all text files).

Binary files are (in general) non-portable – binary files created using C under one operating system can’t be automatically read on another operating          system, unless special procedures are used.

Binary files can only be made portable if we use an internationally-defined standard file format.

Examples of text files: .c files, .txt files, .html files, emails.               Examples of binary files - .mp3 files, .gif files, .wav files, .exe files.

2. Using files – the FILE data structure

C provides a data structure called FILE which enables a whole range of file         manipulation operations to be carried out. This data structure is defined in the stdio.h header file.

In order to use files, the following steps must be taken.

Declare a variable of type FILE

To use files in C, a file variable must be declared. This variable must a pointer to a FILE type, Thus the program statement below declares a variable in_file through which we can carry out file manipulation operations :

FILE* in_file;

Associate the variable with a file using fopen()

The FILE pointer variable is associated with a specific file using the fopen() function which accepts a filename for the file and the access mode (such as    reading or writing). The program statement below opens a file called my_file.dat for read access and attaches the file pointer variable in_file to it :

in_file = fopen("my_file.dat", "r");

The following access permissions are available:

“r” – Opens an existing text file for reading starting at the beginning of the file.

“w” – If the file does not exist, it creates a new text file for writing, - it deletes the current file if it already exists.

“a” – Create a new text file for writing, or write at the end of an existing one.

A “b” may also be used in combination with these access modes (eg. “rb”, “wb”, “ab”) which indicates that a binary file is to be opened.

Note that fopen() returns a NULL if the file open operation fails. For example, this could happen if the file doesn’t exist and the file has been opened for       reading.

Process the data in the file

Appropriate file processing routines are used to manipulate the file data using functions defined in the stdio.h header file. All of these functions use the FILE pointer handle returned by fopen() in order to access the file.

When reading from a text file, a loop (either a while loop or a do-while loop) is used to repeatedly call one of the file reading functions. The loop should           terminate when the end of the file is reached.

When finished, close the file

Thefclose() function closes the file.

fclose(in_file);

The following example program inputs a file name and opens the file. If the file open fails, a message is printed:

#include

int main(void)

{

FILE *input_file;

char filename[20];

printf("Input a filename : ");

scanf("%s",filename);

input_file=fopen(filename,"r");

if (input_file==NULL)

printf("file open failed ");

fclose (input_file);

return 0;

}

Quite often, the code to open a file and test if the opening was successful is given in a single statement:

if ((input_file = fopen(filename,"r"))==NULL)

printf("file open failed ");

3. Character file i/o – getc() and putc()

Single characters may be read from files using the function getc(). This function is used as follows:

int ch;

FILE *in_file;

.

.

ch=getc(in_file);

In this example, in_file is a file handle returned by fopen(). getc() reads as unsigned char a character from the file and returns it in an integer variable. It also returns the value EOF when an end of file is encountered.

EOF is a constant which is defined in stdio.h. It is common to place calls to getc() in a while loop:

int ch;

while ((ch = getc(in_file)) != EOF)

{

......

}

Single characters may be written to files using the function putc(). This function is used as follows:

int ch;

FILE *out_file;

.

.

putc(ch,out_file);

putc() returns the character output as an integer variable.

In the example program shown below, one file is copied to another file             character by character using getc() and putc(). A count is made of the number of characters copied.

In practice, reading files one character at a time makes programs very complex, so this method is rarely used for most applications.

#include

int main(void)

{

FILE *input_file;

FILE *output_file;

char in_filename[20], out_filename[20];

int c, chars_copied=0;

printf("Input the input filename : ");

scanf("%s",in_filename);

printf("Input the output filename : ");

scanf("%s",out_filename);

if ((input_file=fopen(in_filename,"r"))==NULL) printf("input file open failed ");

else

{

if ((output_file=fopen(out_filename,"w"))==NULL) printf("output file open failed ");

else

{

while ((c=getc(input_file))!=EOF) {

putc(c,output_file);

chars_copied++;

}

}

printf("%d characters copied \n",chars_copied);

}

fclose(output_file);

return 0;

}

4. String file i/o - fgets() and fputs()

The function fgets() reads a string of characters from a file into a character array until a newline character is read, an end of file is reached, or until n

characters have been read. A maximum of n-1 characters are read from the file and placed in the string buffer.

Unlike the other file reading functions, fgets returns NULL when the end of the file is reached. Other file read functions usually return EOF upon end-of-file.

The argument n ensures that the buffer char array is never overflowed. This is an extremely useful property. In the example that follows, the program does   not crash even if there is a line longer than MAX_LENGTH characters. Visual     Studio provides the scanf_s operation for “safe reading” from a user or a file,  but it is not part of ANSI C.

The following program uses fgets to read lines from a file and print out their  length using strlen. If a line is longer than MAX_LENGTH characters, then it is read in in blocks of MAX_LENGTH characters.

#define MAX_LENGTH 80

int main(void)

{

char buffer[MAX_LENGTH];

char filename[100];

FILE *fp;

char *c;

printf ("Enter filename:");

scanf ("%s", filename);

fp = fopen(filename, "r");

if (fp == NULL)

printf ("File not found\n");

else

{

do {

if (c = fgets(buffer, MAX_LENGTH, fp))

printf("Length of the line = %d\n", strlen(buffer));

/* Don’t forget string.h */

} while (c != NULL);

fclose(fp); fgets uses “NULL” to check for the end-

return 0; of-file

}

fputs takes a string array and outputs it to a file.


The following program uses the functions fgets() and fputs() to copy a file line by line. It prints out the number of lines copied.