Files#

  • Viewed as streams of bytes

  • All functions are defined at <stdio.h>

  • Files have a name in the OS; represented in C by a FILE structure (which describes their current state)

  • They require opening/closing

  • Can be opened for read/write/append

Working with Files#

FILE *fopen(const char *filename, const char *mode)
/*returns a pointer to the opened file or NULL on failure*/
int *fclose(FILE *fp)
/*returns 0 on success or EOF on failure*/

#include <stdio.h>
int main(void)
{
    FILE *ifp = NULL;
    ifp = fopen("my_file", "r");/*Modes: r, w, a, r+, w+, a+*/
    assert(ifp != NULL);
    fclose(ifp);
}

Character-wise Read/Write#

int fgetc( FILE *);
int fputc( int,  FILE*);

Example: Double-Spacing a File#

The program:

  • Reads the contents of an input file (infile).

  • Writes the contents to an output file (outfile), adding an extra newline after each existing newline (i.e., double-spacing the file).

main()#

#include <stdio.h>
#include <stdlib.h>

// Function prototypes
void double_space(FILE *ifp, FILE *ofp);
void prn_info(const char *pgm_name);
void prn_err_msg(const char *file_name);

int main(int argc, char **argv)
{
    int rtVal = 0;                 // Return value for program exit
    FILE *ifp = NULL, *ofp = NULL; // File pointers

    // Ensure the program is invoked with the correct number of arguments
    if (argc == 3)
    {
        ifp = fopen(argv[1], "r"); // Open input file in read mode
        if (ifp != NULL)
        {
            ofp = fopen(argv[2], "w"); // Open output file in write mode
            if (ofp != NULL)
            {
                double_space(ifp, ofp); // Perform double-spacing
                fclose(ofp);            // Close output file
            }
            else
                rtVal = 2; // Error opening output file
            fclose(ifp);   // Close input file
        }
        else
            rtVal = 1; // Error opening input file
    }
    else
    {
        rtVal = -1;        // Incorrect usage
        prn_info(argv[0]); // Print usage instructions
    }

    // Print error message if applicable
    if (rtVal > 0)
        prn_err_msg(argv[rtVal]);

    return rtVal; // Return appropriate exit code
}

prn_info()#

Prints usage instructions to the user if the program is invoked incorrectly.

void prn_info(const char *pgm_name)
{
    printf("\nUsage: %s infile outfile\n", pgm_name);
    printf("The contents of infile will be double-spaced and written to outfile.\n");
}

prn_err_msg()#

Prints a specific error message if a file cannot be opened.

void prn_err_msg(const char *file_name)
{
    printf("\nError: Could not open file %s\n", file_name);
}

double_space()#

void double_space(FILE *ifp, FILE *ofp)
{
    int c = 0;

    // Read input file character by character
    while ((c = fgetc(ifp)) != EOF)
    {
        fputc(c, ofp); // Write character to output file
        if (c == '\n') // If newline is encountered, add another newline
            fputc('\n', ofp);
    }
}
# @title
%%writefile double_space.c
#include <stdio.h>
#include <stdlib.h>

// Function prototypes
void double_space(FILE *ifp, FILE *ofp);
void prn_info(const char *pgm_name);
void prn_err_msg(const char *file_name);

int main(int argc, char **argv)
{
    int rtVal = 0;                 // Return value for program exit
    FILE *ifp = NULL, *ofp = NULL; // File pointers

    // Ensure the program is invoked with the correct number of arguments
    if (argc == 3)
    {
        ifp = fopen(argv[1], "r"); // Open input file in read mode
        if (ifp != NULL)
        {
            ofp = fopen(argv[2], "w"); // Open output file in write mode
            if (ofp != NULL)
            {
                double_space(ifp, ofp); // Perform double-spacing
                fclose(ofp);            // Close output file
            }
            else
                rtVal = 2; // Error opening output file
            fclose(ifp);   // Close input file
        }
        else
            rtVal = 1; // Error opening input file
    }
    else
    {
        rtVal = -1;        // Incorrect usage
        prn_info(argv[0]); // Print usage instructions
    }

    // Print error message if applicable
    if (rtVal > 0)
        prn_err_msg(argv[rtVal]);

    return rtVal; // Return appropriate exit code
}

void prn_info(const char *pgm_name)
{
    printf("\nUsage: %s infile outfile\n", pgm_name);
    printf("The contents of infile will be double-spaced and written to outfile.\n");
}

void prn_err_msg(const char *file_name)
{
    printf("\nError: Could not open file %s\n", file_name);
}

void double_space(FILE *ifp, FILE *ofp)
{
    int c = 0;

    // Read input file character by character
    while ((c = fgetc(ifp)) != EOF)
    {
        fputc(c, ofp); // Write character to output file
        if (c == '\n') // If newline is encountered, add another newline
            fputc('\n', ofp);
    }
}
  Cell In[1], line 6
    // Function prototypes
    ^
SyntaxError: invalid syntax
# @title
!gcc double_space.c -o double_space
!./double_space infile.txt outfile.txt

Formatted IO#

int fprintf( FILE *fp, const char *control_string, ...);
int fscanf( FILE *fp, const char *control_string, ...);
FILE *fp = fopen("output.txt", "w");
if (fp != NULL)
{
    int age = 25;
    char name[] = "Alice";

    fprintf(fp, "Name: %s, Age: %d\n", name, age);
    fclose(fp);
}

Example: Sum of values#

#include <stdio.h>

int main(void)
{
    int a = 0, sum = 0;
    FILE *ifp = NULL, *ofp = NULL;
    ifp = fopen("my_file", "r");
    ofp = fopen("outfile", "w");
    ...
   
    while (fscanf(ifp, "%d", &a) == 1)
    {
        sum += a;
    }

    fprintf(ofp, "The sum is %d.\n", sum);

    fclose(ifp);
    fclose(ofp);

    return 0;
}

Standard file pointers#

In stdio.h:

stdin standard input file connected to the keyboard

stdout standard output file connected to the screen

stderr standard error file connected to the screen

fprintf( stdout, ... );  /*is equivalent to*/  printf( ....);
fscanf( stdin, ...); /*is equivalent to*/ scanf( .... );

Binary files#

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

Reads at most size*nmemb bytes (characters) from the file *stream into the array ptr. Reading stops when EOF is encountered. Returns the number of read bytes.

size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);

Writes the first size*nmemb bytes in the array ptr into the file *stream. Returns the number of successfully written bytes.

# @title
%%writefile write_binary.c
#include <stdio.h>
#include <stdlib.h>

// Define a student structure
typedef struct {
    int id;
    char name[50];
    float grade;
} Student;

int main() {
    Student students[] = {
        {1, "Alice", 90.5},
        {2, "Bob", 85.3},
        {3, "Charlie", 78.9}
    };
    FILE *file = fopen("students.dat", "wb");
    if (!file) {
        perror("Error opening file");
        return 1;
    }

    // Write array of structures to the binary file
    fwrite(students, sizeof(Student), 3, file);
    fclose(file);

    printf("Data written to binary file successfully.\n");
    return 0;
}
# @title
!gcc write_binary.c -o write_binary
!./write_binary
# @title
%%writefile read_binary.c
#include <stdio.h>
#include <stdlib.h>

// Define a student structure
typedef struct {
    int id;
    char name[50];
    float grade;
} Student;

int main() {
    Student students[3]; // Array to hold the data read
    FILE *file = fopen("students.dat", "rb");
    if (!file) {
        perror("Error opening file");
        return 1;
    }

    // Read array of structures from the binary file
    fread(students, sizeof(Student), 3, file);
    fclose(file);

    // Print the read data
    printf("Student Records:\n");
    for (int i = 0; i < 3; ++i) {
        printf("ID: %d, Name: %s, Grade: %.2f\n",
               students[i].id, students[i].name, students[i].grade);
    }
    return 0;
}
# @title
!gcc read_binary.c -o read_binary
!./read_binary

Change the Case of Letters in a File#

#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#define   BUFSIZE   1024

int main(int argc, char **argv)
{
	char	mybuf[BUFSIZE] = { 0 }, *p = NULL;
	FILE   *ifp = NULL, *ofp = NULL;
	int    n = 0;

	ifp  = fopen(argv[1], "r"); /*open the file for reading*/
	ofp = fopen(argv[2], "w"); /*open the file for writing*/
	assert(ifp != NULL);
	assert(ofp != NULL);

	while ((n = fread(mybuf, sizeof(char), BUFSIZE, ifp)) > 0) /*read from the file*/
	{
		for (p = mybuf; p - mybuf < n; ++p)
		{
		      if (islower(*p))        *p = toupper(*p);
		      else if (isupper(*p))   *p = tolower(*p);
		}
		fwrite(mybuf, sizeof(char), n, ofp); /*write to the file*/
	}
  /*close the files*/
	fclose(ifp);
	fclose(ofp);
	return 0;
}

Random access to files: fseek and ftell#

/* no need to define!!! already defined
#define  SEEK_SET   0 beginning of the file

#define  SEEK_CUR   1 current position in the file

#define  SEEK_END   2 end of the file
*/

int fseek(FILE *fp, long offset, int place);
(returns 0 on success and non-zero on failure)

void rewind(FILE *fp);

long ftell(FILE *fp);
(returns current position or -1 on failure)

Example: Write a File Backwards#

#include <stdio.h>
#include <assert.h>
#define MAXSTRING 100

int main(void) {
    char file_name[MAXSTRING] = {0};
    int c = 0;
    FILE *ifp = NULL;

    printf("\nInput a file name: ");
    scanf("%s", file_name);

    ifp = fopen(file_name, "r");
    assert(ifp != NULL);

    // Move to the end of the file
    fseek(ifp, 0, SEEK_END);

    // Get the file size
    long pos = ftell(ifp);

    // Backtrack through the file
    while (pos > 0) {
        fseek(ifp, -1, SEEK_CUR); // Move back one character
        c = fgetc(ifp);           // Read the character
        putchar(c);               // Print it
        fseek(ifp, -1, SEEK_CUR); // Adjust position for the next iteration
        pos--;
    }

    fclose(ifp);
    return 0;
}

Additional IO functions#

int feof(FILE *fp);
/*non-zero when true and 0 when false*/
char *fgets(char *buf, int buf_size, FILE *fp);
/*appends ‘\0’; returns buf on success and NULL o/w*/
int fputs(const char *str, FILE *fp)
/*removes ‘\0’; returns >=0 on success and EOF o/w*/
int fflush(FILE *fp)
/*flushes on writing; returns 0 on success and EOF o/w*/

int sprintf(char *s , const char *format, ...);
int sscanf(const char *s, const char *format, ...);