Introduction To Stream

Introduction

Streams in C provide a unified interface for input and output operations. A stream is an abstraction that represents a flow of data between the program and external devices like files, keyboard, screen, or network. Understanding streams is fundamental for performing file operations and input/output in C programming.

Key Concepts

Stream: Abstract representation of data flow File Pointer: Variable that points to a stream Buffer: Temporary storage area for stream data Standard Streams: Pre-defined streams (stdin, stdout, stderr) Text Stream: Stream for character data with line ending conversion Binary Stream: Stream for binary data without conversion

Standard Streams

Pre-defined Stream Pointers

#include <stdio.h>

int main() {
    printf("Introduction to Standard Streams:\n\n");
    
    // stdin - Standard Input Stream (keyboard)
    printf("Enter your name: ");
    char name[50];
    fgets(name, sizeof(name), stdin);
    
    // stdout - Standard Output Stream (screen)
    printf("Hello, %s", name);
    fprintf(stdout, "This is also written to stdout\n");
    
    // stderr - Standard Error Stream (screen, usually)
    fprintf(stderr, "This is an error message\n");
    
    // Display stream properties
    printf("\nStream Information:\n");
    printf("stdin address: %p\n", (void*)stdin);
    printf("stdout address: %p\n", (void*)stdout);
    printf("stderr address: %p\n", (void*)stderr);
    
    return 0;
}

Working with Standard Streams

#include <stdio.h>
#include <string.h>

// Function to demonstrate stream redirection concepts
void demonstrateStreams() {
    char buffer[100];
    
    printf("=== Standard Stream Operations ===\n");
    
    // Reading from stdin
    printf("Enter a sentence: ");
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // Remove newline if present
        buffer[strcspn(buffer, "\n")] = 0;
        
        // Output to stdout
        fprintf(stdout, "You entered: %s\n", buffer);
        
        // Output to stderr
        fprintf(stderr, "Debug: String length is %zu\n", strlen(buffer));
    }
    
    // Demonstrating formatted output to different streams
    printf("Normal output (stdout)\n");
    fprintf(stderr, "Error output (stderr)\n");
    fprintf(stdout, "Explicit stdout output\n");
}

int main() {
    demonstrateStreams();
    return 0;
}

File Streams

Opening and Closing Streams

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

int main() {
    FILE *filePtr;
    
    printf("File Stream Operations:\n");
    
    // Opening a file stream for writing
    filePtr = fopen("sample.txt", "w");
    if (filePtr == NULL) {
        fprintf(stderr, "Error: Could not open file for writing\n");
        return 1;
    }
    
    // Writing to file stream
    fprintf(filePtr, "Hello, File Streams!\n");
    fprintf(filePtr, "This is line 2\n");
    fprintf(filePtr, "Numbers: %d, %f\n", 42, 3.14);
    
    // Closing the file stream
    fclose(filePtr);
    printf("Data written to sample.txt\n");
    
    // Opening file stream for reading
    filePtr = fopen("sample.txt", "r");
    if (filePtr == NULL) {
        fprintf(stderr, "Error: Could not open file for reading\n");
        return 1;
    }
    
    // Reading from file stream
    char line[100];
    printf("\nReading from file:\n");
    while (fgets(line, sizeof(line), filePtr) != NULL) {
        printf("Read: %s", line);
    }
    
    // Closing the file stream
    fclose(filePtr);
    
    return 0;
}

File Stream Modes

#include <stdio.h>
#include <string.h>

// Function to demonstrate different file modes
void demonstrateFileModes() {
    FILE *fp;
    char data[100];
    
    printf("=== File Stream Modes ===\n");
    
    // Write mode ("w") - creates new file or overwrites existing
    fp = fopen("test_write.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "Write mode test\n");
        fprintf(fp, "This overwrites existing content\n");
        fclose(fp);
        printf("Write mode: File created/overwritten\n");
    }
    
    // Append mode ("a") - creates new file or appends to existing
    fp = fopen("test_append.txt", "a");
    if (fp != NULL) {
        fprintf(fp, "Append mode test\n");
        fprintf(fp, "This adds to existing content\n");
        fclose(fp);
        printf("Append mode: Content appended\n");
    }
    
    // Read mode ("r") - opens existing file for reading
    fp = fopen("test_write.txt", "r");
    if (fp != NULL) {
        printf("Read mode: Reading from file:\n");
        while (fgets(data, sizeof(data), fp) != NULL) {
            printf("  %s", data);
        }
        fclose(fp);
    }
    
    // Read/Write mode ("r+") - opens existing file for reading and writing
    fp = fopen("test_write.txt", "r+");
    if (fp != NULL) {
        // Read current content
        fgets(data, sizeof(data), fp);
        printf("Current first line: %s", data);
        
        // Move to beginning and write
        rewind(fp);
        fprintf(fp, "Modified first line\n");
        fclose(fp);
        printf("Read/Write mode: File modified\n");
    }
}

int main() {
    demonstrateFileModes();
    return 0;
}

Stream Operations

Character Stream Operations

#include <stdio.h>

// Function for character-based stream operations
void characterStreamOperations() {
    FILE *fp;
    char ch;
    
    printf("=== Character Stream Operations ===\n");
    
    // Create a test file
    fp = fopen("char_test.txt", "w");
    if (fp != NULL) {
        // Writing characters to stream
        fputc('H', fp);
        fputc('e', fp);
        fputc('l', fp);
        fputc('l', fp);
        fputc('o', fp);
        fputc('\n', fp);
        
        // Writing string character by character
        char *message = "Stream Operations";
        for (int i = 0; message[i] != '\0'; i++) {
            fputc(message[i], fp);
        }
        fputc('\n', fp);
        
        fclose(fp);
        printf("Characters written to file\n");
    }
    
    // Reading characters from stream
    fp = fopen("char_test.txt", "r");
    if (fp != NULL) {
        printf("Reading characters from stream:\n");
        
        while ((ch = fgetc(fp)) != EOF) {
            putchar(ch);  // Write to stdout
        }
        
        fclose(fp);
    }
}

// Function for line-based stream operations
void lineStreamOperations() {
    FILE *fp;
    char line[100];
    
    printf("\n=== Line Stream Operations ===\n");
    
    // Writing lines to stream
    fp = fopen("line_test.txt", "w");
    if (fp != NULL) {
        fputs("First line of text\n", fp);
        fputs("Second line of text\n", fp);
        fputs("Third line without newline", fp);
        fclose(fp);
        printf("Lines written to file\n");
    }
    
    // Reading lines from stream
    fp = fopen("line_test.txt", "r");
    if (fp != NULL) {
        printf("Reading lines from stream:\n");
        
        int lineNumber = 1;
        while (fgets(line, sizeof(line), fp) != NULL) {
            printf("Line %d: %s", lineNumber++, line);
        }
        printf("\n");
        
        fclose(fp);
    }
}

int main() {
    characterStreamOperations();
    lineStreamOperations();
    return 0;
}

Formatted Stream Operations

#include <stdio.h>

// Structure for demonstration
struct Student {
    int id;
    char name[50];
    float gpa;
};

// Function for formatted stream operations
void formattedStreamOperations() {
    FILE *fp;
    struct Student student;
    
    printf("=== Formatted Stream Operations ===\n");
    
    // Writing formatted data to stream
    fp = fopen("student_data.txt", "w");
    if (fp != NULL) {
        // Writing formatted data
        fprintf(fp, "Student Records\n");
        fprintf(fp, "===============\n");
        fprintf(fp, "ID: %d\n", 1001);
        fprintf(fp, "Name: %s\n", "John Doe");
        fprintf(fp, "GPA: %.2f\n", 3.85);
        fprintf(fp, "Status: %s\n", "Active");
        
        // Writing multiple records
        fprintf(fp, "\nAll Students:\n");
        fprintf(fp, "%-5s %-20s %-5s\n", "ID", "Name", "GPA");
        fprintf(fp, "%-5d %-20s %-5.2f\n", 1001, "John Doe", 3.85);
        fprintf(fp, "%-5d %-20s %-5.2f\n", 1002, "Jane Smith", 3.92);
        fprintf(fp, "%-5d %-20s %-5.2f\n", 1003, "Bob Johnson", 3.67);
        
        fclose(fp);
        printf("Formatted data written to file\n");
    }
    
    // Reading formatted data from stream
    fp = fopen("student_data.txt", "r");
    if (fp != NULL) {
        char line[100];
        printf("Reading formatted data:\n");
        
        // Read and display first few lines
        for (int i = 0; i < 5 && fgets(line, sizeof(line), fp) != NULL; i++) {
            printf("%s", line);
        }
        
        fclose(fp);
    }
}

// Function demonstrating scanf with streams
void scanfStreamOperations() {
    FILE *fp;
    int id;
    char name[50];
    float gpa;
    
    printf("\n=== Scanf Stream Operations ===\n");
    
    // Create data file for reading
    fp = fopen("input_data.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "1001 Alice_Johnson 3.85\n");
        fprintf(fp, "1002 Bob_Smith 3.92\n");
        fprintf(fp, "1003 Carol_Brown 3.67\n");
        fclose(fp);
    }
    
    // Reading formatted data using fscanf
    fp = fopen("input_data.txt", "r");
    if (fp != NULL) {
        printf("Reading with fscanf:\n");
        
        while (fscanf(fp, "%d %s %f", &id, name, &gpa) == 3) {
            printf("Student: ID=%d, Name=%s, GPA=%.2f\n", id, name, gpa);
        }
        
        fclose(fp);
    }
}

int main() {
    formattedStreamOperations();
    scanfStreamOperations();
    return 0;
}

Binary Streams

Binary Stream Operations

#include <stdio.h>
#include <string.h>

// Structure for binary operations
struct Employee {
    int empId;
    char name[50];
    float salary;
    int active;
};

// Function for binary stream operations
void binaryStreamOperations() {
    FILE *fp;
    struct Employee emp1, emp2, readEmp;
    
    printf("=== Binary Stream Operations ===\n");
    
    // Initialize employee data
    emp1.empId = 101;
    strcpy(emp1.name, "Alice Wilson");
    emp1.salary = 55000.0;
    emp1.active = 1;
    
    emp2.empId = 102;
    strcpy(emp2.name, "Bob Miller");
    emp2.salary = 62000.0;
    emp2.active = 1;
    
    // Writing binary data to stream
    fp = fopen("employees.dat", "wb");
    if (fp != NULL) {
        // Write structures as binary data
        fwrite(&emp1, sizeof(struct Employee), 1, fp);
        fwrite(&emp2, sizeof(struct Employee), 1, fp);
        
        fclose(fp);
        printf("Binary data written to file\n");
    }
    
    // Reading binary data from stream
    fp = fopen("employees.dat", "rb");
    if (fp != NULL) {
        printf("Reading binary data:\n");
        
        // Read structures from binary file
        while (fread(&readEmp, sizeof(struct Employee), 1, fp) == 1) {
            printf("Employee: ID=%d, Name=%s, Salary=%.2f, Active=%s\n",
                   readEmp.empId, readEmp.name, readEmp.salary,
                   readEmp.active ? "Yes" : "No");
        }
        
        fclose(fp);
    }
}

// Function for mixed binary operations
void mixedBinaryOperations() {
    FILE *fp;
    int numbers[] = {10, 20, 30, 40, 50};
    char text[] = "Binary Stream Example";
    int readNumbers[5];
    char readText[50];
    
    printf("\n=== Mixed Binary Operations ===\n");
    
    // Writing mixed binary data
    fp = fopen("mixed_data.dat", "wb");
    if (fp != NULL) {
        // Write array of integers
        fwrite(numbers, sizeof(int), 5, fp);
        
        // Write string length and string
        int textLen = strlen(text) + 1;  // Include null terminator
        fwrite(&textLen, sizeof(int), 1, fp);
        fwrite(text, sizeof(char), textLen, fp);
        
        fclose(fp);
        printf("Mixed binary data written\n");
    }
    
    // Reading mixed binary data
    fp = fopen("mixed_data.dat", "rb");
    if (fp != NULL) {
        // Read array of integers
        if (fread(readNumbers, sizeof(int), 5, fp) == 5) {
            printf("Numbers read: ");
            for (int i = 0; i < 5; i++) {
                printf("%d ", readNumbers[i]);
            }
            printf("\n");
        }
        
        // Read string length and string
        int textLen;
        if (fread(&textLen, sizeof(int), 1, fp) == 1) {
            if (textLen < sizeof(readText) && 
                fread(readText, sizeof(char), textLen, fp) == textLen) {
                printf("Text read: %s\n", readText);
            }
        }
        
        fclose(fp);
    }
}

int main() {
    binaryStreamOperations();
    mixedBinaryOperations();
    return 0;
}

Stream Positioning

File Position Operations

#include <stdio.h>
#include <string.h>

// Function to demonstrate stream positioning
void streamPositioning() {
    FILE *fp;
    char data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char buffer[10];
    long position;
    
    printf("=== Stream Positioning ===\n");
    
    // Create test file
    fp = fopen("position_test.txt", "w");
    if (fp != NULL) {
        fputs(data, fp);
        fclose(fp);
    }
    
    // Demonstrate positioning operations
    fp = fopen("position_test.txt", "r");
    if (fp != NULL) {
        // Read first 5 characters
        fread(buffer, sizeof(char), 5, fp);
        buffer[5] = '\0';
        printf("First 5 chars: %s\n", buffer);
        
        // Get current position
        position = ftell(fp);
        printf("Current position: %ld\n", position);
        
        // Seek to position 10
        fseek(fp, 10, SEEK_SET);
        fread(buffer, sizeof(char), 5, fp);
        buffer[5] = '\0';
        printf("Chars at position 10: %s\n", buffer);
        
        // Seek relative to current position
        fseek(fp, 5, SEEK_CUR);
        fread(buffer, sizeof(char), 3, fp);
        buffer[3] = '\0';
        printf("Chars after seeking +5: %s\n", buffer);
        
        // Seek from end of file
        fseek(fp, -5, SEEK_END);
        fread(buffer, sizeof(char), 5, fp);
        buffer[5] = '\0';
        printf("Last 5 chars: %s\n", buffer);
        
        // Rewind to beginning
        rewind(fp);
        fread(buffer, sizeof(char), 3, fp);
        buffer[3] = '\0';
        printf("After rewind: %s\n", buffer);
        
        fclose(fp);
    }
}

int main() {
    streamPositioning();
    return 0;
}

Stream Buffering

Buffer Control Operations

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

// Function to demonstrate stream buffering
void streamBuffering() {
    FILE *fp;
    char *buffer;
    char data[] = "This is a test of stream buffering\n";
    
    printf("=== Stream Buffering ===\n");
    
    // Create file for testing
    fp = fopen("buffer_test.txt", "w");
    if (fp != NULL) {
        // Default buffering
        printf("Writing with default buffering...\n");
        fputs("Line 1: Default buffering\n", fp);
        
        // Flush explicitly
        fflush(fp);
        printf("Buffer flushed explicitly\n");
        
        // Set line buffering
        setvbuf(fp, NULL, _IOLBF, 0);
        fputs("Line 2: Line buffering\n", fp);
        
        // Set full buffering with custom buffer
        buffer = malloc(1024);
        if (buffer != NULL) {
            setvbuf(fp, buffer, _IOFBF, 1024);
            fputs("Line 3: Full buffering with custom buffer\n", fp);
        }
        
        fclose(fp);
        free(buffer);
    }
    
    // Read and display file content
    fp = fopen("buffer_test.txt", "r");
    if (fp != NULL) {
        char line[100];
        printf("File contents:\n");
        while (fgets(line, sizeof(line), fp) != NULL) {
            printf("  %s", line);
        }
        fclose(fp);
    }
}

// Function to demonstrate unbuffered output
void unbufferedOutput() {
    FILE *fp;
    
    printf("\n=== Unbuffered Stream ===\n");
    
    fp = fopen("unbuffered_test.txt", "w");
    if (fp != NULL) {
        // Set no buffering
        setvbuf(fp, NULL, _IONBF, 0);
        
        printf("Writing to unbuffered stream...\n");
        fputs("Unbuffered output line 1\n", fp);
        fputs("Unbuffered output line 2\n", fp);
        
        fclose(fp);
        printf("Unbuffered write completed\n");
    }
}

int main() {
    streamBuffering();
    unbufferedOutput();
    return 0;
}

Error Handling with Streams

Stream Error Detection

#include <stdio.h>
#include <errno.h>
#include <string.h>

// Function to demonstrate stream error handling
void streamErrorHandling() {
    FILE *fp;
    char buffer[100];
    
    printf("=== Stream Error Handling ===\n");
    
    // Attempt to open non-existent file
    fp = fopen("nonexistent_file.txt", "r");
    if (fp == NULL) {
        printf("Error opening file: %s\n", strerror(errno));
        printf("errno value: %d\n", errno);
    } else {
        fclose(fp);
    }
    
    // Create a file and test error conditions
    fp = fopen("error_test.txt", "w");
    if (fp != NULL) {
        fputs("Test data for error handling\n", fp);
        fclose(fp);
    }
    
    // Open for reading and test error conditions
    fp = fopen("error_test.txt", "r");
    if (fp != NULL) {
        // Normal read
        if (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("Successfully read: %s", buffer);
        }
        
        // Try to read past end of file
        if (fgets(buffer, sizeof(buffer), fp) == NULL) {
            if (feof(fp)) {
                printf("End of file reached\n");
            }
            if (ferror(fp)) {
                printf("Error occurred during reading\n");
            }
        }
        
        // Clear error flags
        clearerr(fp);
        printf("Error flags cleared\n");
        
        fclose(fp);
    }
}

int main() {
    streamErrorHandling();
    return 0;
}

Important Points

  1. Streams abstract data flow between program and external devices
  2. Three standard streams (stdin, stdout, stderr) are automatically available
  3. File streams must be opened and closed explicitly
  4. Text streams handle character data with possible line ending conversion
  5. Binary streams handle raw binary data without conversion
  6. Stream positioning allows random access to file data
  7. Buffering improves performance but can affect immediate output
  8. Error checking is important for robust stream operations

Best Practices

  1. Always check return values of stream operations
  2. Close all opened streams to free resources
  3. Use appropriate file modes for intended operations
  4. Handle end-of-file conditions properly
  5. Check for errors using ferror() and errno
  6. Flush buffers when immediate output is needed
  7. Use binary mode for non-text data
  8. Validate file operations before proceeding

Summary

Streams in C provide a unified interface for input/output operations, abstracting the details of different devices and storage systems. Standard streams (stdin, stdout, stderr) are automatically available, while file streams require explicit opening and closing. Understanding stream concepts, buffering, positioning, and error handling is essential for effective file I/O programming in C.


Part of BCA Programming with C Course (UGCOA22J201)