Cat in C

Below is a simple example of a C program that opens two files for reading, concatenates their contents, and writes the result to a third file.

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

int main() {
    // File pointers for input and output files
    FILE *file1, *file2, *outputFile;

    // Open the first file for reading
    file1 = fopen("input1.txt", "r");
    if (file1 == NULL) {
        perror("Error opening file1 for reading");
        exit(EXIT_FAILURE);
    }

    // Open the second file for reading
    file2 = fopen("input2.txt", "r");
    if (file2 == NULL) {
        perror("Error opening file2 for reading");
        fclose(file1);
        exit(EXIT_FAILURE);
    }

    // Open the third file for writing
    outputFile = fopen("output.txt", "w");
    if (outputFile == NULL) {
        perror("Error opening output file for writing");
        fclose(file1);
        fclose(file2);
        exit(EXIT_FAILURE);
    }

    // Concatenate the contents of file1 and file2
    int ch;
    while ((ch = fgetc(file1)) != EOF) {
        fputc(ch, outputFile);
    }

    while ((ch = fgetc(file2)) != EOF) {
        fputc(ch, outputFile);
    }

    // Close all the files
    fclose(file1);
    fclose(file2);
    fclose(outputFile);

    printf("Files concatenated successfully.\n");

    return 0;
}

This program assumes that you have two input files named "input1.txt" and "input2.txt" in the same directory as the executable. It creates an output file named "output.txt" containing the concatenated content.

Remember to replace the file names with the actual names of your input files. Additionally, make sure you have the necessary permissions to read from the input files and write to the output file.

Let's go through the details of the provided C program step by step:

  1. Include Headers:

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

    These lines include necessary header files. <stdio.h> is for input and output operations, and <stdlib.h> is for functions involving memory allocation and program control.

  2. Main Function:

     int main() {
    

    The program starts execution from the main function.

  3. File Pointers:

     FILE *file1, *file2, *outputFile;
    

    Three file pointers are declared: file1 for the first input file, file2 for the second input file, and outputFile for the output file.

  4. Open Input Files:

     file1 = fopen("input1.txt", "r");
     file2 = fopen("input2.txt", "r");
    

    The fopen function is used to open the input files ("input1.txt" and "input2.txt") for reading ("r" mode). If any file fails to open, an error message is printed, and the program exits with a failure status.

  5. Open Output File:

     outputFile = fopen("output.txt", "w");
    

    The fopen function is used to open the output file ("output.txt") for writing ("w" mode). If the output file fails to open, an error message is printed, and the program exits with a failure status.

  6. Concatenate Contents:

     int ch;
     while ((ch = fgetc(file1)) != EOF) {
         fputc(ch, outputFile);
     }
     while ((ch = fgetc(file2)) != EOF) {
         fputc(ch, outputFile);
     }
    

    The program uses fgetc to read characters from file1 and file2 one by one until the end of file (EOF) is reached. The characters are then written to outputFile using fputc. This process effectively concatenates the contents of the two input files into the output file.

  7. Close Files:

     fclose(file1);
     fclose(file2);
     fclose(outputFile);
    

    After reading from and writing to files, it's important to close them using fclose to release system resources.

  8. Print Success Message:

     printf("Files concatenated successfully.\n");
    

    If the program reaches this point, it prints a success message indicating that the files were concatenated successfully.

  9. Return:

     return 0;
    

    The main function returns 0 to indicate successful execution to the operating system.

This program is a simple file concatenation utility. It's important to note that it assumes the existence of input files ("input1.txt" and "input2.txt") and creates an output file ("output.txt") in the same directory as the executable. Also, error handling is included to handle cases where files cannot be opened successfully.

Using fread and fwrite with a buffer can be more efficient than using fgetc and fputc when dealing with large amounts of data. Here's the modified program:

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

#define BUFFER_SIZE 1024

int main() {
    FILE *file1, *file2, *outputFile;
    char buffer[BUFFER_SIZE];
    size_t bytesRead;

    // Open the first file for reading
    file1 = fopen("file1.txt", "rb");
    if (file1 == NULL) {
        perror("Error opening file1.txt");
        return EXIT_FAILURE;
    }

    // Open the second file for reading
    file2 = fopen("file2.txt", "rb");
    if (file2 == NULL) {
        perror("Error opening file2.txt");
        fclose(file1);
        return EXIT_FAILURE;
    }

    // Open a third file for writing
    outputFile = fopen("output.txt", "wb");
    if (outputFile == NULL) {
        perror("Error opening output.txt");
        fclose(file1);
        fclose(file2);
        return EXIT_FAILURE;
    }

    // Copy content from file1 to outputFile using fread/fwrite and a buffer
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), file1)) > 0) {
        fwrite(buffer, 1, bytesRead, outputFile);
    }

    // Copy content from file2 to outputFile using fread/fwrite and a buffer
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), file2)) > 0) {
        fwrite(buffer, 1, bytesRead, outputFile);
    }

    // Close all the files
    fclose(file1);
    fclose(file2);
    fclose(outputFile);

    printf("Files concatenated successfully using fread/fwrite.\n");

    return EXIT_SUCCESS;
}

In this version, the program uses a buffer (char buffer[BUFFER_SIZE]) to read and write data in chunks, making it more efficient than reading and writing one character at a time. The BUFFER_SIZE constant can be adjusted based on the specific needs of your program. Using buffered I/O can significantly reduce the number of system calls and improve performance, especially for large files.

Let's go through the program step by step:

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

#define BUFFER_SIZE 1024

int main() {
    FILE *file1, *file2, *outputFile;
    char buffer[BUFFER_SIZE];
    size_t bytesRead;
  • The program starts by including necessary header files (stdio.h and stdlib.h), defining a constant BUFFER_SIZE for the size of the buffer, and declaring variables. Three file pointers (file1, file2, and outputFile) are declared, along with a character array (buffer) to store data read from the files. The bytesRead variable will be used to keep track of the number of bytes read or written.
    // Open the first file for reading
    file1 = fopen("file1.txt", "rb");
    if (file1 == NULL) {
        perror("Error opening file1.txt");
        return EXIT_FAILURE;
    }
  • The program opens the first file (file1.txt) for reading in binary mode ("rb"). If the file opening fails, an error message is printed using perror, and the program exits with a failure status.
    // Open the second file for reading
    file2 = fopen("file2.txt", "rb");
    if (file2 == NULL) {
        perror("Error opening file2.txt");
        fclose(file1);
        return EXIT_FAILURE;
    }
  • Similarly, the second file (file2.txt) is opened for reading in binary mode. If the opening fails, an error message is printed, and the program closes the first file (file1) before exiting with a failure status.
    // Open a third file for writing
    outputFile = fopen("output.txt", "wb");
    if (outputFile == NULL) {
        perror("Error opening output.txt");
        fclose(file1);
        fclose(file2);
        return EXIT_FAILURE;
    }
  • The third file (output.txt) is opened for writing in binary mode. If the opening fails, an error message is printed, and the program closes the previously opened files (file1 and file2) before exiting with a failure status.
    // Copy content from file1 to outputFile using fread/fwrite and a buffer
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), file1)) > 0) {
        fwrite(buffer, 1, bytesRead, outputFile);
    }
  • The program then enters a loop where it reads data from file1 using fread into the buffer. The loop continues as long as there are bytes read (bytesRead > 0). The data in the buffer is then written to outputFile using fwrite. This process is repeated until the entire content of file1 is read and written.
    // Copy content from file2 to outputFile using fread/fwrite and a buffer
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), file2)) > 0) {
        fwrite(buffer, 1, bytesRead, outputFile);
    }
  • The program repeats a similar process for file2, reading its content into the buffer and writing it to outputFile. This ensures that the content of both files is concatenated in the output.txt file.
    // Close all the files
    fclose(file1);
    fclose(file2);
    fclose(outputFile);

    printf("Files concatenated successfully using fread/fwrite.\n");

    return EXIT_SUCCESS;
}
  • Finally, the program closes all the opened files using fclose. If everything is successful, it prints a success message and returns with a success status (EXIT_SUCCESS). If there are any errors during file operations, the program exits with a failure status (EXIT_FAILURE).
0
Subscribe to my newsletter

Read articles from Jyotiprakash Mishra directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jyotiprakash Mishra
Jyotiprakash Mishra

I am Jyotiprakash, a deeply driven computer systems engineer, software developer, teacher, and philosopher. With a decade of professional experience, I have contributed to various cutting-edge software products in network security, mobile apps, and healthcare software at renowned companies like Oracle, Yahoo, and Epic. My academic journey has taken me to prestigious institutions such as the University of Wisconsin-Madison and BITS Pilani in India, where I consistently ranked among the top of my class. At my core, I am a computer enthusiast with a profound interest in understanding the intricacies of computer programming. My skills are not limited to application programming in Java; I have also delved deeply into computer hardware, learning about various architectures, low-level assembly programming, Linux kernel implementation, and writing device drivers. The contributions of Linus Torvalds, Ken Thompson, and Dennis Ritchie—who revolutionized the computer industry—inspire me. I believe that real contributions to computer science are made by mastering all levels of abstraction and understanding systems inside out. In addition to my professional pursuits, I am passionate about teaching and sharing knowledge. I have spent two years as a teaching assistant at UW Madison, where I taught complex concepts in operating systems, computer graphics, and data structures to both graduate and undergraduate students. Currently, I am an assistant professor at KIIT, Bhubaneswar, where I continue to teach computer science to undergraduate and graduate students. I am also working on writing a few free books on systems programming, as I believe in freely sharing knowledge to empower others.