BIL 104E Introduction to Scientific and Engineering Computing Lecture 12
Files v.s. Streams In C, a file can refer to a disk file, a terminal, a printer, or a tape drive. In other words, a file represents a concrete device with which you want to exchange information. Before you perform any communication to a file, you have to open the file. Then you need to close the opened file after you finish exchanging information with it. The data flow you transfer from your program to a file, or vice versa, is called a stream, which is a series of bytes. Not like a file, a stream is device-independent. All streams have the same behavior. To perform I/O operations, you can read from or write to any type of files by simply associating a stream to the file. There are two formats of streams. The first one is called the text stream, which consists of a sequence of characters (that is, ASCII data). Depending on the compilers, each character line in a text stream may be terminated by a newline character. Text streams are used for textual data, which has a consistent appearance from one environment to another, or from one machine to another. The second format of streams is called the binary stream, which is a series of bytes. The content of an.exe file would be one example. Binary streams are primarily used for nontextual data, which is required to keep the exact contents of the file. 10/4/11 Lecture 12 2
I/O Statements Each file used in a program must have a file pointer associated with it. A file pointer is defined with a FILE declaration. FILE data type is defined in the header file stdio.h. After a file pointer is defined, it must be associated with a specific file. The fopen function obtains the information needed to assign a file pointer to a specific file. The two arguments for this function are the file name and a character that indicates the file status, which is also called the file open mode. If we are going to read information from a file with a program, the file open mode is r for read. If we are going to write information to a file with a program, the file open mode is w for write. The fclose function is used to close a file after we are finished with it. The function argument is the file pointer. 10/4/11 Lecture 12 3
File Opening Modes "r" opens an existing text file for reading. "w" creates a text file for writing. "a" opens an existing text file for appending. "r+" opens an existing text file for reading or writing. "w+" creates a text file for reading or writing. "a+" opens or creates a text file for appending. "rb" opens an existing binary file for reading. "wb" creates a binary file for writing. "ab" opens an existing binary file for appending. "r+b" opens an existing binary file for reading or writing. "w+b" creates a binary file for reading or writing. "a+b" opens or creates a binary file for appending. Note that you might see people use the mode "rb+" instead of "r+b". These two strings are equivalent. Similarly, "wb+" is the same as "w+b"; "ab+" is equivalent to "a+b". 10/4/11 Lecture 12 4
/* Opening and closing a file */ #include <stdio.h> enum {SUCCESS, FAIL; main(void) { FILE *fptr; char filename[]= "haiku.txt"; int reval = SUCCESS; if ((fptr = fopen(filename, "r")) == NULL){ printf("cannot open %s.\n", filename); reval = FAIL; else { printf("the value of fptr: 0x%p\n", fptr); printf("ready to close the file."); fclose(fptr); return reval; 10/4/11 Lecture 12 5
fgetc and fputc functions The fgetc and fputc functions are used to read/write one character at a time. The int fgetc(file *stream) function fetches the next character from the stream specified by stream. The function then returns the value of an int that is converted from the character. The int fputc(int c, FILE *stream) function prints the character that corresponds to the integer argument to the specified file stream. It then returns the same character as the function value if it is successful; otherwise, it returns EOF. After a character is written, fputc() advances the associated file pointer. 10/4/11 Lecture 12 6
/* Reading and writing one character at a time */ #include <stdio.h> enum {SUCCESS, FAIL; void CharReadWrite(FILE *fin, FILE *fout); main(void) { FILE *fptr1, *fptr2; char filename1[]= "outhaiku.txt"; char filename2[]= "haiku.txt"; int reval = SUCCESS; if ((fptr1 = fopen(filename1, "w")) == NULL) { printf("cannot open %s.\n", filename1); reval = FAIL; else if ((fptr2 = fopen(filename2, "r")) == NULL) { printf("cannot open %s.\n", filename2); reval = FAIL; else { CharReadWrite(fptr2, fptr1); fclose(fptr1); fclose(fptr2); return reval; void CharReadWrite(FILE *fin, FILE *fout) { int c; while ((c=fgetc(fin))!= EOF){ /* write to a file */ fputc(c, fout); /* put the character */ /*on the screen */ putchar(c); 10/4/11 Lecture 12 7
fgets Function The fgets function is used to read one line of text at a time. The char *fgets (char *s, int n, FILE *stream) function: Here s references a character array that is used to store characters read from the opened file pointed to by the file pointer stream. n specifies the maximum number of array elements. If it is successful, it returns the char pointer s. If an error occurs, the function returns a null pointer, and the contents of the array are unknown. The fgets() function can read up to n-1 characters, and can append a null character after the last character fetched, until a newline or an EOF is encountered. If a newline is encountered during the reading, the fgets() function includes the newline in the array. Note, this is different from what gets() function does. The gets() function just replaces the newline character with a null character. If EOF is encountered, the fgets() function returns a null pointer and leaves the array untouched. 10/4/11 Lecture 12 8
fputs Function The fputs function is used to write one line of text at a time. The int fputs (const char *s, FILE *stream) function: Here s points to the array that contains the characters to be written to a file associated with the file pointer stream. The const modifier indicates that the content of the array pointed to by s cannot be changed. If it fails, the fputs() function returns a nonzero value; otherwise, it returns zero. Note that the character array must include a null character at the end as the terminator to the fputs() function. Also, unlike the puts() function, the fputs() function does not insert a newline character to the string written to a file. 10/4/11 Lecture 12 9
/* Reading and writing one line of text at a time */ #include <stdio.h> enum {SUCCESS, FAIL, MAX_LEN = 81; void LineReadWrite (FILE *fin, FILE *fout); main(void) { FILE *fptr1, *fptr2; char filename1[]= "outhaiku.txt"; char filename2[]= "haiku.txt"; int reval = SUCCESS; if ((fptr1 = fopen (filename1, "w")) == NULL){ printf ("Cannot open %s for writing.\n", filename1); reval = FAIL; else if ((fptr2 = fopen (filename2, "r")) == NULL){ printf ("Cannot open %s for reading.\n", filename2); reval = FAIL; else { LineReadWrite(fptr2, fptr1); fclose (fptr1); fclose (fptr2); return reval; void LineReadWrite(FILE *fin, FILE *fout) { char buff[max_len]; while (fgets (buff, MAX_LEN, fin)!= NULL){ fputs (buff, fout); printf ("%s", buff); 10/4/11 Lecture 12 10
fread Function The fread function is used to read one block of characters at a time. The size_t fread (void *ptr, size_t size, size_t n, FILE *stream) function: Here ptr is a pointer to 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 an integral type defined in the header file stdio.h. The fread() function returns the number of elements actually read. The number of elements read by the fread() function should be equal to the value specified by the third argument to the function, unless an error occurs or an EOF (end-of-file) is encountered. The fread() function returns the number of elements that are actually read, if an error occurs or an EOF is encountered. 10/4/11 Lecture 12 11
fwrite Function The fwrite function is used to write one block of characters at a time. The size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream) function: Here 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 fwrite() function returns the number of elements actually written. If there is no error occurring, the number returned by fwrite() should be the same as the third argument in the function. The return value may be less than the specified value if an error occurs. Note that it's the programmer's responsibility to ensure that the array is large enough to hold data for either the fread() function or the fwrite() function. 10/4/11 Lecture 12 12
feof Function The feof function can be used to determine when the end of a file is encountered. The int feof (FILE *stream) function Here stream is the file pointer that is associated with an opened file. The feof() function returns 0 if the end of the file has not been reached; otherwise, it returns a nonzero integer. This function is more useful when a binary file is read because the values of some bytes may be equal to the value of EOF. If the end of a binary file is determined by checking the value returned by fread(), we may end up at the wrong position. Using the feof() function helps us to avoid mistakes in determining the end of a file. 10/4/11 Lecture 12 13
/*Reading and writing one block at a time */ #include <stdio.h> enum {SUCCESS, FAIL, MAX_LEN = 80; void BlockReadWrite(FILE *fin, FILE *fout); int ErrorMsg(char *str); main(void) { FILE *fptr1, *fptr2; char filename1[]= "outhaiku.txt"; char filename2[]= "haiku.txt"; int reval = SUCCESS; if ((fptr1 = fopen(filename1, "w")) == NULL){ reval = ErrorMsg(filename1); else if ((fptr2 = fopen(filename2, "r")) == NULL){ reval = ErrorMsg(filename2); else { BlockReadWrite(fptr2, fptr1); return reval; fclose(fptr1); fclose(fptr2); void BlockReadWrite(FILE *fin, FILE *fout) { int num; char buff[max_len + 1]; while (!feof(fin)){ num = fread(buff, sizeof(char), MAX_LEN, fin); /* append a null character */ buff[num * sizeof(char)] = '\0'; printf("%s", buff); fwrite(buff, sizeof(char), num, fout); int ErrorMsg(char *str) { printf("cannot open %s.\n", str); return FAIL; 10/4/11 Lecture 12 14
fscanf function Once an input file and its pointer have been specified, information can be read from it by using the fscanf function. fscanf statement converts the characters from the lines in the data file to values. Example: Each line in the sensor1.dat file contains a time and sensor reading: #include <stdio.h> FILE *sensor1; sensor1 = fopen("sensor1.dat","r"); fscanf(sensor1, "%lf %lf", &time, &motion); fclose(sensor1); 10/4/11 Lecture 12 15
fprintf function If the file is an output file, we can write information to the file with the fprintf function. Example: #include <stdio.h> FILE *balloon; balloon = fopen("balloon.dat", "w"); fprintf (balloon, "%f %f %f\n", time, height, velocity/3600); fclose(balloon); 10/4/11 Lecture 12 16
/* This program generates a summary report from a data file */ /* that has the number of data points in the first record. */ #include <stdio.h> #incude <stdlib.h> #define FILENAME "sensor1.dat" main(){ int num_data_pts, k; double time, motion, sum=0, maximum, minimum; FILE *sensor1; sensor1 = fopen (FILENAME, "r"); fscanf (sensor1, "%i", &num_data_pts); for (k=1; k<=num_data_pts; k++);{ fscanf (sensor1, "%lf %lf", &time, &motion); if (k == 1) maximum = minimum = motion; sum += motion; if (motion > maximum) maximum = motion; if (motion < minimum) minimum = motion; printf ("Number of sensor readings: %i \n", num_data_pts); printf ("Average reading : %.2f \n", sum/num_data_pts); printf ("Maximum reading : %.2f \n", maximum); printf ("Minimum reading : %.2f \n", minimum); fclose (sensor1); return EXIT_SUCCESS; 10 0.0 132.5 0.1 147.2 0.2 148.3 0.3 157.3 0.4 163.2 0.5 158.2 0.6 169.3 0.7 148.2 0.8 137.6 0.9 135.9 10/4/11 Lecture 12 17
/* This program generates a summary report from a data file */ /* that has a trailer record with negative values*/ #include <stdio.h> #incude <stdlib.h> #define FILENAME "sensor2.dat" main(){ int num_data_pts=0, k; double time, motion, sum=0, maximum, minimum; FILE *sensor2; sensor2 = fopen (FILENAME, "r"); fscanf (sensor2, "%lf %lf", &time, &motion); maximum = minimum = motion; do{ sum += motion; if (motion > maximum) maximum = motion; if (motion < minimum) minimum = motion; num_data_pts++; fscanf(sensor2, "%lf %lf", &time, &motion); while (time >= 0); printf ("Number of sensor readings : %i \n", num_data_pts); printf ("Average reading : %.2f \n", sum/num_data_pts); printf ("Maximum reading : %.2f \n", maximum); printf ("Minimum reading : %.2f \n", minimum); fclose (sensor2); return EXIT_SUCCESS; 0.0 132.5 0.1 147.2 0.2 148.3 0.3 157.3 0.4 163.2 0.5 158.2 0.6 169.3 0.7 148.2 0.8 137.6 0.9 135.9-99 -99 10/4/11 Lecture 12 18
/* This program generates a summary report from a data file */ /* that does not have a header record or a trailer record */ #include <stdio.h> #incude <stdlib.h> #define FILENAME "sensor3.dat" 0.0 132.5 main(){ 0.1 147.2 int num_data_pts=0, k; 0.2 148.3 double time, motion, sum=0, maximum, minimum; 0.3 157.3 FILE *sensor3; 0.4 163.2 sensor3 = fopen (FILENAME, "r"); 0.5 158.2 while (( fscanf (sensor3, "%lf %lf", &time, &motion)) ==2){ 0.6 169.3 num_data_pts++; 0.7 148.2 if (num_data_pts ==1) maximum = minimum = motion; 0.8 137.6 sum += motion; 0.9 135.9 if (motion > maximum) maximum = motion; if (motion < minimum) minimum = motion; printf ("Number of sensor readings : %i \n", num_data_pts); printf ("Average reading : %.2f \n", sum/num_data_pts); printf ("Maximum reading : %.2f \n", maximum); printf ("Minimum reading : %.2f \n", minimum); fclose (sensor3); return EXIT_SUCCESS; 10/4/11 Lecture 12 19