File

File

File operations in C

Written by: saeed1907057

Wed, 20 Nov 2024

Introduction

  • File handling in C allows us to store and retrieve data from files.
  • This is very useful for creating programs that need to save data permanently.

Basic operations on File

File handling refers to working with files for tasks like:

  • Reading data from files(Read).
  • Writing data to files(Write).
  • Updating or appending data to existing files(Update).
  • Delete data from files(Delete).
  • FILE * pointer is used to access a file.

Opening a File

  • To open a file, we use the fopen() function.
  • Structure is:
    FILE *file = fopen("file_name.extension", "mode")
    
  • mode specifies how the file should be opened. Some are
    • r
      • Read mode.
      • Returns NULL if file can't be opened or doesn't exist.
      • It doesn't create new file.
    • w
      • Write mode
      • It creates a new file or overwrites an existing one.
      • Overwrites deletes the old content and make the file blank.
    • a
      • Append mode
      • It opens the existing file or create new one then sets the pointer to the last character.
      • Unlike w, it doesn't overwrite the file content.
    • r+
      • Read and write.
      • Sets the pointer to the first character of the file.
      • It doesn't create new file.
    • w+
      • Read and write.
      • It creates new file or overwrite existing content.
    • a+
      • Append and read.
      • Creates new file if doesn't exists.
      • Sets the pointer to the end same as a.
    • rb, wb, rb+, wb+
      • These are for binary files.
      • Used for reading non-text data like image, audio etc.

Reading file

  • Reading by character by character

    • File content (data.txt)
      ASDFGH
      QWERTY
      
    • Code
      #include<stdio.h>
      int main(){
      
          FILE* file = fopen("files/data.txt", "r");
          if(file == NULL) { printf("File not found\n"); return 1; }
      
          char ch;
          while( (ch = fgetc(file)) != EOF) {
              printf("%c", ch);
          }
          fclose(file);
      
          return 0;
      }
      
      • fgetc takes the file pointer and returns a char or EOF at that position.
    • Output
      ASDFGH
      QWERTY
      
  • Reading by line by line

    • File content (data.txt)

      ABC CBA
      123
      DEF
      321
      
    • Code

      #include<stdio.h>
      
      int main(){
      
          FILE* file = fopen("files/data.txt", "r");
          if(file == NULL) { printf("File not found\n"); return 1; }
      
          char line[50];
          int lineNo = 1;
          while( fgets(line, 50, file) ) {
              printf("%d: %s", lineNo, line);
              lineNo++;
          }
          fclose(file);
      
          return 0;
      }
      
      • fgets
        • Structure
          fgets(char * destination, int size, FILE * fptr);
          
        • It will read at most size - 1 character from that line.
    • Output

      1: ABC CBA
      2: 123
      3: DEF
      4: 321
      
  • Reading file data using format specifiers

    • We can read data like scanf function using fscanf function.
    • fscanf is similar to scanf, but it takes the file ptr as parameter followed by others.
      int fscanf(FILE *ptr, const char *format, ...);
      
    • Assume file(data.txt) contains roll name age in each line.
      1907002 Sina 21
      1907030 Abdullah 22
      1907046 Saif 23
      
    • Code for reading:
      #include<stdio.h>
      int main(){
      
          FILE* file = fopen("files/data.txt", "r");
          if(file == NULL) { printf("File not found\n"); return 1; }
      
          int roll, age;
          char name[50];
      
          printf("%-10s %-20s %-5s\n", "Roll", "Name", "Age");
          while ( fscanf(file, "%d %s %d", &roll, name, &age) != EOF) {
              printf("%-10d %-20s %-5d\n", roll, name, age);
          }
          fclose(file);
          return 0;
      }
      
    • Output
      Roll       Name                 Age  
      1907002    Sina                 21
      1907030    Abdullah             22
      1907046    Saif                 23
      

Writing to a File

  • Use fprintf() or fputs() to write to a file.
  • Simple writing

    • Code
      #include<stdio.h>
      int main(){
          FILE* file = fopen("files/content.txt", "w");
          if(file == NULL) { printf("Error\n"); return 1; }
      
          fprintf(file, "%d %s %d\n", 1, "John", 20);
          fprintf(file, "%d %s %d\n", 2, "Doe", 25);
      
          fclose(file);
          return 0;
      }
      
    • File content(content.txt)
      1 John 20
      2 Doe 25
      
  • Appending to end of the file

    • Suppose we want to write 3 Sun 53 at the end of the previos file(content.txt). Code
      #include<stdio.h>
      int main(){
          FILE* file = fopen("files/content.txt", "a");
          if(file == NULL) { printf("Error\n"); return 1; }
      
          fprintf(file, "%d %s %d\n", 3, "Sun", 53);
      
          fclose(file);
          return 0;
      }
      
    • Updated file content
      1 John 20
      2 Doe 25
      3 Sun 53
      
      • See, only the last line is added. Rest remains the same.

Updating the content of a file

  • Let's say we want to round the age by 10. Like: 25 will be replaced by 30, 57 will be replaced by 60.
  • For updating a file, we will create a temporary file with our updated data. Then remove the old data, and rename temporary file.
  • Code(Way-1)(Using a temporary file):
    #include<stdio.h>
    
    int main(){
    
        FILE* file = fopen("files/content.txt", "r+");
        if(file == NULL) { printf("Error\n"); return 1; }
    
        int roll, age;
        char name[50];
    
        FILE *temp = fopen("files/temp.txt", "w");
    
        while ( fscanf(file, "%d %s %d", &roll, name, &age) != EOF) {
            
            int rem = age % 10;
            if(rem < 5) age -= rem;
            else age += (10 - rem);
    
            // age = ((age + 5) / 10) * 10;
            fprintf(temp, "%d %s %d\n", roll, name, age);
        }
    
        fclose(file);
        fclose(temp);
    
        remove("files/content.txt");
        rename("files/temp.txt", "files/content.txt");
        return 0;
    }
    
  • Code(Way-2)(Using fseek)
    #include<stdio.h>
    
    int getNumLength(int num){
        int length = 0;
        while( num > 0 ){
            num /= 10;
            length++;
        }
        return length;
    }
    
    int main(){
    
        FILE* file = fopen("files/content.txt", "r+");
        if(file == NULL) { printf("Error\n"); return 1; }
    
        int roll, age;
        char name[50];
    
        while ( fscanf(file, "%d %s %d", &roll, name, &age) != EOF) {
            int oldAge = age;
            
            age = ((age + 5) / 10) * 10;
    
            int numLength = getNumLength(age);
            int newNumLength = getNumLength(oldAge);
            
            // moving the file pointer to the correct position
            int position = ftell(file) - numLength;
            fseek(file, position, SEEK_SET);
    
            // writing the new age
            fprintf(file, "%d", age);
    
            // moving the file pointer to the next line
            position += newNumLength;
            fseek(file, position, SEEK_SET);
        }
    
        fclose(file);
        return 0;
    }
    
  • Output
    1 John 20
    2 Doe 30
    3 Sun 50
    

Closing a File

  • Always close a file using fclose() when done.
  • It ensures that file is closed properly and data from buffer is cleared and written in file.
    fclose(file);
    

Reading and writing binary files

  • Why do we need binary format?

    • It represents data exactly as it was.
      • Unlike text files, binary files do not interpret or translate the data (e.g., newline conversions like \n to \r\n on Windows).
      • An integer 1234 in binary format stores its actual 4-byte binary representation, not its ASCII text equivalent.
    • It is faster and can read/write as chunks.
    • It takes relatively less storage than normal representation.
    • It allows us to store and retrive complex data structure like struct without conversion.
  • Saving & Reading entire array

    • We can do it using fwrite function.

    • Code:

      #include<stdio.h>
      int main(){
      
          FILE* file = fopen("files/content.bin", "wb");
          if(file == NULL) { printf("Error\n"); return 1; }
      
          int arr[5] = {1, 2, 3, 4, 5};
      
          fwrite(arr, sizeof(int), 5, file); // 5 is the len of the array
          fclose(file);
          return 0;
      }
      
    • File content(content.bin)

      next image

      • See content is not redable while previewing since data are in binary format.
    • But if we read the array using code like this:

      #include<stdio.h>
      int main(){
          FILE* file = fopen("files/content.bin", "rb");
          if(file == NULL) { printf("Error\n"); return 1; }
      
          int arr[5];
          fread(arr, sizeof(int), 5, file);
          
          for(int i = 0; i < 5; i++){
              printf("%d ", arr[i]);
          }
          printf("\n");
          fclose(file);
          return 0;
      }
      
    • Output:

      1 2 3 4 5
      
      • See, this was our actual array.
  • Saving & Reading struct

    • As like before, we can do it using fwrite.
    • Code:
      #include<stdio.h>
      
      struct Student{
          char name[20];
          int age;
          float marks;
      };
      
      int main(){
      
          struct Student sami = {"Sami", 21, 90.5};
          struct Student panda = {"Panda", 22, 85.5};
      
          FILE* file = fopen("files/student.bin", "wb");
          if(file == NULL) { printf("Error\n"); return 1; }
      
          fwrite(&sami, sizeof(struct Student), 1, file);
          fwrite(&panda, sizeof(struct Student), 1, file);
          
          fclose(file);
          return 0;
      }
      
    • Content on file(student.bin)
      慓業          䊵慐摮a         䊫
      
    • Retrieving from file
      #include<stdio.h>
      
      struct Student{
          char name[20];
          int age;
          float marks;
      };
      
      int main(){
      
          struct Student sami, panda;
      
          FILE* file = fopen("files/student.bin", "rb");
          if(file == NULL) { printf("Error\n"); return 1; }
      
          fread(&sami, sizeof(struct Student), 1, file);
          fread(&panda, sizeof(struct Student), 1, file);
          
          printf("%s %d %.2f\n", sami.name, sami.age, sami.marks);
          printf("%s %d %.2f\n", panda.name, panda.age, panda.marks);
          
          fclose(file);
          return 0;
      }
      
    • Output:
      Sami 21 90.50
      Panda 22 85.50
      

That's the end of our C journey. Welcome to the computer world.

"The only way to do great work is to love what you do."
— Steve Jobs

User12024-11-02

This is a comment 1.

User12024-11-02

This is a comment 2.