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
- Streams abstract data flow between program and external devices
- Three standard streams (stdin, stdout, stderr) are automatically available
- File streams must be opened and closed explicitly
- Text streams handle character data with possible line ending conversion
- Binary streams handle raw binary data without conversion
- Stream positioning allows random access to file data
- Buffering improves performance but can affect immediate output
- Error checking is important for robust stream operations
Best Practices
- Always check return values of stream operations
- Close all opened streams to free resources
- Use appropriate file modes for intended operations
- Handle end-of-file conditions properly
- Check for errors using ferror() and errno
- Flush buffers when immediate output is needed
- Use binary mode for non-text data
- 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)