# 5. File Input/Output

### 5.1 Why File I/O?

So far, all our programs lose their data when they terminate. **File I/O** allows programs to:
- Save data permanently
- Read data from external sources
- Create logs and reports
- Share data between programs

**Python vs C File Operations:**

| Python | C |
|--------|---|
| `f = open("file.txt", "r")` | `FILE *f = fopen("file.txt", "r");` |
| `f.write("text")` | `fprintf(f, "text");` |
| `content = f.read()` | `fscanf(f, "%s", buffer);` |
| `f.close()` | `fclose(f);` |

### 5.2 File Pointer

In C, files are accessed through **file pointers** of type `FILE*`:

```c
FILE *filePointer;
```

The `FILE` type is defined in `<stdio.h>`.

### 5.3 Opening Files - fopen()

**Function Signature:**
```c
FILE *fopen(const char *filename, const char *mode);
```

**File Opening Modes:**

| Mode | Description | If File Exists | If File Doesn't Exist |
|------|-------------|----------------|----------------------|
| `"r"` | Read only | Opens file | Returns NULL |
| `"w"` | Write only | Overwrites content | Creates new file |
| `"a"` | Append | Appends to end | Creates new file |
| `"r+"` | Read and write | Opens file | Returns NULL |
| `"w+"` | Read and write | Overwrites content | Creates new file |
| `"a+"` | Read and append | Opens file | Creates new file |
| `"rb"` | Read binary | Opens file | Returns NULL |
| `"wb"` | Write binary | Overwrites content | Creates new file |
| `"ab"` | Append binary | Appends to end | Creates new file |

**Example:**
```c
FILE *file;

// Open file for reading
file = fopen("data.txt", "r");

// Always check if file opened successfully
if (file == NULL) {
    printf("Error: Could not open file!\n");
    return 1;
}

// ... file operations ...

fclose(file);
```

### 5.4 Closing Files - fclose()

**Always close files after use** to:
- Free system resources
- Ensure all data is written to disk
- Prevent data corruption

```c
int fclose(FILE *filePointer);
```

**Returns:**
- `0` on success
- `EOF` on error

**Example:**
```c
FILE *file = fopen("data.txt", "r");
if (file != NULL) {
    // ... operations ...
    fclose(file);
}
```

### 5.5 Reading from Text Files

#### 5.5.1 fscanf() - Formatted Input

Similar to `scanf()`, but reads from a file:

```c
int fscanf(FILE *stream, const char *format, ...);
```

**Example:**
```c
FILE *file = fopen("numbers.txt", "r");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

int num;
while (fscanf(file, "%d", &num) == 1) {
    printf("Read: %d\n", num);
}

fclose(file);
```

#### 5.5.2 fgets() - Line Input

Reads a line from a file:

```c
char *fgets(char *str, int n, FILE *stream);
```

**Example:**
```c
FILE *file = fopen("text.txt", "r");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

char line[256];
while (fgets(line, sizeof(line), file) != NULL) {
    printf("%s", line);
}

fclose(file);
```

#### 5.5.3 fgetc() - Character Input

Reads a single character:

```c
int fgetc(FILE *stream);
```

**Example:**
```c
FILE *file = fopen("text.txt", "r");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

int ch;
while ((ch = fgetc(file)) != EOF) {
    putchar(ch);
}

fclose(file);
```

### 5.6 Writing to Text Files

#### 5.6.1 fprintf() - Formatted Output

Similar to `printf()`, but writes to a file:

```c
int fprintf(FILE *stream, const char *format, ...);
```

**Example:**
```c
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

fprintf(file, "Student ID: %d\n", 12345);
fprintf(file, "Name: %s\n", "Alice Johnson");
fprintf(file, "GPA: %.2f\n", 3.75);

fclose(file);
```

#### 5.6.2 fputs() - String Output

Writes a string to a file:

```c
int fputs(const char *str, FILE *stream);
```

**Example:**
```c
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

fputs("Hello, World!\n", file);
fputs("This is a test.\n", file);

fclose(file);
```

#### 5.6.3 fputc() - Character Output

Writes a single character:

```c
int fputc(int char, FILE *stream);
```

**Example:**
```c
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
    printf("Error opening file!\n");
    return 1;
}

for (char ch = 'A'; ch <= 'Z'; ch++) {
    fputc(ch, file);
}

fclose(file);
```

### 5.7 File Position Functions

#### 5.7.1 fseek() - Move File Pointer

```c
int fseek(FILE *stream, long offset, int origin);
```

**Origin values:**
- `SEEK_SET` - Beginning of file
- `SEEK_CUR` - Current position
- `SEEK_END` - End of file

**Example:**
```c
FILE *file = fopen("data.txt", "r");

// Move to beginning
fseek(file, 0, SEEK_SET);

// Move 10 bytes from current position
fseek(file, 10, SEEK_CUR);

// Move to end of file
fseek(file, 0, SEEK_END);
```

#### 5.7.2 ftell() - Get Current Position

```c
long ftell(FILE *stream);
```

**Example:**
```c
FILE *file = fopen("data.txt", "r");
long position = ftell(file);
printf("Current position: %ld\n", position);
```

#### 5.7.3 rewind() - Reset to Beginning

```c
void rewind(FILE *stream);
```

**Example:**
```c
FILE *file = fopen("data.txt", "r");

// Read some data...

rewind(file);  // Go back to beginning
```

### 5.8 Checking End of File - feof()

```c
int feof(FILE *stream);
```

**Returns non-zero if end of file is reached.**

**Example:**
```c
FILE *file = fopen("data.txt", "r");
char ch;

while (!feof(file)) {
    ch = fgetc(file);
    if (ch != EOF) {
        putchar(ch);
    }
}

fclose(file);
```

### 5.9 Practical Example: Student Records Manager

```c
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[50];
    float gpa;
    int age;
} Student;

// Save student to file
void saveStudent(const char *filename, Student s) {
    FILE *file = fopen(filename, "a");  // Append mode
    if (file == NULL) {
        printf("Error opening file!\n");
        return;
    }
    
    fprintf(file, "%d,%s,%.2f,%d\n", s.id, s.name, s.gpa, s.age);
    fclose(file);
    
    printf("Student record saved successfully!\n");
}

// Load all students from file
void loadStudents(const char *filename) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("No records found!\n");
        return;
    }
    
    Student s;
    printf("\n=== Student Records ===\n");
    
    while (fscanf(file, "%d,%49[^,],%f,%d\n", 
                  &s.id, s.name, &s.gpa, &s.age) == 4) {
        printf("ID: %d | Name: %s | GPA: %.2f | Age: %d\n",
               s.id, s.name, s.gpa, s.age);
    }
    
    fclose(file);
}

// Search for student by ID
int searchStudent(const char *filename, int searchID) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("Error opening file!\n");
        return 0;
    }
    
    Student s;
    while (fscanf(file, "%d,%49[^,],%f,%d\n", 
                  &s.id, s.name, &s.gpa, &s.age) == 4) {
        if (s.id == searchID) {
            printf("\n--- Student Found ---\n");
            printf("ID: %d\n", s.id);
            printf("Name: %s\n", s.name);
            printf("GPA: %.2f\n", s.gpa);
            printf("Age: %d\n", s.age);
            fclose(file);
            return 1;
        }
    }
    
    fclose(file);
    printf("Student not found!\n");
    return 0;
}

int main() {
    int choice;
    Student s;
    
    do {
        printf("\n=== Student Management System ===\n");
        printf("1. Add Student\n");
        printf("2. View All Students\n");
        printf("3. Search Student by ID\n");
        printf("4. Exit\n");
        printf("Enter choice: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                printf("\nEnter Student ID: ");
                scanf("%d", &s.id);
                
                printf("Enter Student Name: ");
                scanf(" %[^\n]", s.name);
                
                printf("Enter Student GPA: ");
                scanf("%f", &s.gpa);
                
                printf("Enter Student Age: ");
                scanf("%d", &s.age);
                
                saveStudent("students.txt", s);
                break;
                
            case 2:
                loadStudents("students.txt");
                break;
                
            case 3: {
                int searchID;
                printf("\nEnter Student ID to search: ");
                scanf("%d", &searchID);
                searchStudent("students.txt", searchID);
                break;
            }
                
            case 4:
                printf("Exiting program...\n");
                break;
                
            default:
                printf("Invalid choice!\n");
        }
    } while (choice != 4);
    
    return 0;
}
```

### 5.10 Binary File Operations

Binary files store data in raw binary format, which is more efficient for storing structures.

#### 5.10.1 Writing Binary Data - fwrite()

```c
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
```

**Parameters:**
- `ptr` - Pointer to data to write
- `size` - Size of each element
- `nmemb` - Number of elements
- `stream` - File pointer

**Example:**
```c
typedef struct {
    int id;
    char name[50];
    float gpa;
} Student;

Student s = {12345, "Alice Johnson", 3.75};

FILE *file = fopen("students.dat", "wb");
if (file != NULL) {
    fwrite(&s, sizeof(Student), 1, file);
    fclose(file);
}
```

#### 5.10.2 Reading Binary Data - fread()

```c
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
```

**Parameters:**
- `ptr` - Pointer to memory where data will be stored
- `size` - Size of each element
- `nmemb` - Number of elements
- `stream` - File pointer

**Example:**
```c
Student s;

FILE *file = fopen("students.dat", "rb");
if (file != NULL) {
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        printf("ID: %d, Name: %s, GPA: %.2f\n", 
               s.id, s.name, s.gpa);
    }
    fclose(file);
}
```

#### 5.10.3 Binary vs Text Files

| Aspect | Text Files | Binary Files |
|--------|-----------|--------------|
| **Human Readable** | Yes | No |
| **Size** | Larger | Smaller |
| **Speed** | Slower | Faster |
| **Portability** | More portable | Less portable |
| **Precision** | May lose precision | Full precision |
| **Best for** | Configuration files, logs | Large data, structures |

### 5.11 Complete Binary File Example

```c
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[50];
    float gpa;
    int age;
} Student;

// Save student to binary file
void saveStudentBinary(const char *filename, Student s) {
    FILE *file = fopen(filename, "ab");  // Append binary
    if (file == NULL) {
        printf("Error opening file!\n");
        return;
    }
    
    fwrite(&s, sizeof(Student), 1, file);
    fclose(file);
    
    printf("Student saved to binary file!\n");
}

// Load all students from binary file
void loadStudentsBinary(const char *filename) {
    FILE *file = fopen(filename, "rb");  // Read binary
    if (file == NULL) {
        printf("No records found!\n");
        return;
    }
    
    Student s;
    printf("\n=== Student Records (Binary) ===\n");
    
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        printf("ID: %d | Name: %s | GPA: %.2f | Age: %d\n",
               s.id, s.name, s.gpa, s.age);
    }
    
    fclose(file);
}

// Count number of records in binary file
int countRecords(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        return 0;
    }
    
    // Seek to end of file
    fseek(file, 0, SEEK_END);
    
    // Get file size
    long fileSize = ftell(file);
    
    fclose(file);
    
    // Calculate number of records
    return fileSize / sizeof(Student);
}

// Update student record by ID
int updateStudent(const char *filename, int id, Student newData) {
    FILE *file = fopen(filename, "rb+");  // Read and write binary
    if (file == NULL) {
        printf("Error opening file!\n");
        return 0;
    }
    
    Student s;
    int found = 0;
    long position = 0;
    
    // Search for student
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        if (s.id == id) {
            // Move back to the position of this record
            fseek(file, position, SEEK_SET);
            
            // Write updated data
            fwrite(&newData, sizeof(Student), 1, file);
            
            found = 1;
            printf("Student record updated!\n");
            break;
        }
        position = ftell(file);
    }
    
    fclose(file);
    
    if (!found) {
        printf("Student ID %d not found!\n", id);
    }
    
    return found;
}

// Delete student record by ID
int deleteStudent(const char *filename, int id) {
    FILE *file = fopen(filename, "rb");
    FILE *temp = fopen("temp.dat", "wb");
    
    if (file == NULL || temp == NULL) {
        printf("Error opening files!\n");
        return 0;
    }
    
    Student s;
    int found = 0;
    
    // Copy all records except the one to delete
    while (fread(&s, sizeof(Student), 1, file) == 1) {
        if (s.id == id) {
            found = 1;
            continue;  // Skip this record
        }
        fwrite(&s, sizeof(Student), 1, temp);
    }
    
    fclose(file);
    fclose(temp);
    
    // Replace original file with temp file
    remove(filename);
    rename("temp.dat", filename);
    
    if (found) {
        printf("Student record deleted!\n");
    } else {
        printf("Student ID %d not found!\n", id);
    }
    
    return found;
}

int main() {
    int choice;
    Student s;
    
    do {
        printf("\n=== Student Management System (Binary Files) ===\n");
        printf("1. Add Student\n");
        printf("2. View All Students\n");
        printf("3. Count Records\n");
        printf("4. Update Student\n");
        printf("5. Delete Student\n");
        printf("6. Exit\n");
        printf("Enter choice: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                printf("\nEnter Student ID: ");
                scanf("%d", &s.id);
                
                printf("Enter Student Name: ");
                scanf(" %[^\n]", s.name);
                
                printf("Enter Student GPA: ");
                scanf("%f", &s.gpa);
                
                printf("Enter Student Age: ");
                scanf("%d", &s.age);
                
                saveStudentBinary("students.dat", s);
                break;
                
            case 2:
                loadStudentsBinary("students.dat");
                break;
                
            case 3: {
                int count = countRecords("students.dat");
                printf("\nTotal records: %d\n", count);
                break;
            }
                
            case 4: {
                int updateID;
                printf("\nEnter Student ID to update: ");
                scanf("%d", &updateID);
                
                printf("Enter new Student Name: ");
                scanf(" %[^\n]", s.name);
                
                printf("Enter new Student GPA: ");
                scanf("%f", &s.gpa);
                
                printf("Enter new Student Age: ");
                scanf("%d", &s.age);
                
                s.id = updateID;
                updateStudent("students.dat", updateID, s);
                break;
            }
                
            case 5: {
                int deleteID;
                printf("\nEnter Student ID to delete: ");
                scanf("%d", &deleteID);
                deleteStudent("students.dat", deleteID);
                break;
            }
                
            case 6:
                printf("Exiting program...\n");
                break;
                
            default:
                printf("Invalid choice!\n");
        }
    } while (choice != 6);
    
    return 0;
}
```