mirror of
https://github.com/nicbarker/clay.git
synced 2025-12-23 17:41:06 +00:00
Complete learning guide covering ALL C concepts from beginner to advanced: Main Guide (LEARNING_C_WITH_CLAY.md): - Added Chapters 3-5: Operators, Control Flow, Loops - Enhanced Chapters 6-13: Functions, Pointers, Structs, Arrays, Strings, Type Casting, Storage Classes, Recursion - All chapters include extensive Clay library examples - Progressive difficulty from basics to advanced topics Specialized Tutorial Files (docs/): - 14_bit_manipulation.md: Comprehensive bit operations guide * Bitwise operators, masks, flags * Counting bits, power of 2 operations * Practical applications with Clay examples - 21_standard_library.md: C Standard Library overview * stdio.h, stdlib.h, string.h, math.h * Clay's zero-dependency approach * Custom implementations vs stdlib - 22_file_io.md: Complete File I/O guide * Text and binary file operations * Configuration files for Clay apps * Error handling and best practices - 23_command_line_arguments.md: CLI argument parsing * argc/argv basics * Flag parsing and subcommands * Clay application configuration examples - README_C_TUTORIALS.md: Master index and learning guide * Complete chapter overview * Learning path recommendations * Progress tracking checklist * Prerequisites and setup instructions Features: - 24 comprehensive chapters covering all C concepts - 100+ code examples with detailed explanations - Real-world patterns from Clay library throughout - Practice exercises for each chapter - Modular organization for easy navigation - Zero-dependency programming concepts - Professional C development practices Total content: ~70,000+ words of detailed tutorials
14 KiB
14 KiB
Chapter 22: File I/O in C
Complete Guide with Clay Library Examples
22.1 Introduction to File I/O
C provides file operations through stdio.h:
- Open files
- Read/write data
- Close files
- Navigate file position
- Check file status
Clay's Approach: Clay doesn't do file I/O - it's a UI layout library. But applications using Clay need file operations for saving/loading UI state, configurations, etc.
22.2 Opening and Closing Files
Basic File Operations
#include <stdio.h>
int main(void) {
FILE *file;
// Open file for writing
file = fopen("output.txt", "w");
if (file == NULL) {
printf("Error opening file!\n");
return 1;
}
// Write to file
fprintf(file, "Hello, File!\n");
// Close file
fclose(file);
return 0;
}
File Modes
| Mode | Description | Creates if not exists | Truncates existing |
|---|---|---|---|
"r" |
Read only | No | No |
"w" |
Write only | Yes | Yes |
"a" |
Append | Yes | No |
"r+" |
Read/Write | No | No |
"w+" |
Read/Write | Yes | Yes |
"a+" |
Read/Append | Yes | No |
"rb" |
Read binary | No | No |
"wb" |
Write binary | Yes | Yes |
FILE *fr = fopen("input.txt", "r"); // Read text
FILE *fw = fopen("output.txt", "w"); // Write text
FILE *fa = fopen("log.txt", "a"); // Append text
FILE *fb = fopen("data.bin", "rb"); // Read binary
22.3 Writing to Files
fprintf - Formatted Output
#include <stdio.h>
int main(void) {
FILE *file = fopen("data.txt", "w");
if (file == NULL) {
return 1;
}
int age = 25;
float height = 5.9f;
char name[] = "John";
// Write formatted data
fprintf(file, "Name: %s\n", name);
fprintf(file, "Age: %d\n", age);
fprintf(file, "Height: %.1f\n", height);
fclose(file);
return 0;
}
fputs - Write String
#include <stdio.h>
int main(void) {
FILE *file = fopen("output.txt", "w");
if (file == NULL) return 1;
fputs("Line 1\n", file);
fputs("Line 2\n", file);
fputs("Line 3\n", file);
fclose(file);
return 0;
}
fputc - Write Character
#include <stdio.h>
int main(void) {
FILE *file = fopen("output.txt", "w");
if (file == NULL) return 1;
fputc('H', file);
fputc('i', file);
fputc('\n', file);
fclose(file);
return 0;
}
fwrite - Write Binary Data
#include <stdio.h>
typedef struct {
int id;
char name[50];
float salary;
} Employee;
int main(void) {
FILE *file = fopen("employees.dat", "wb");
if (file == NULL) return 1;
Employee emp = {1, "John Doe", 50000.0f};
// Write struct to binary file
size_t written = fwrite(&emp, sizeof(Employee), 1, file);
if (written != 1) {
printf("Write error!\n");
}
fclose(file);
return 0;
}
22.4 Reading from Files
fscanf - Formatted Input
#include <stdio.h>
int main(void) {
FILE *file = fopen("data.txt", "r");
if (file == NULL) return 1;
char name[50];
int age;
float height;
// Read formatted data
fscanf(file, "Name: %s\n", name);
fscanf(file, "Age: %d\n", &age);
fscanf(file, "Height: %f\n", &height);
printf("Name: %s, Age: %d, Height: %.1f\n", name, age, height);
fclose(file);
return 0;
}
fgets - Read Line
#include <stdio.h>
int main(void) {
FILE *file = fopen("input.txt", "r");
if (file == NULL) return 1;
char buffer[256];
// Read line by line
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}
fclose(file);
return 0;
}
fgetc - Read Character
#include <stdio.h>
int main(void) {
FILE *file = fopen("input.txt", "r");
if (file == NULL) return 1;
int ch;
// Read character by character
while ((ch = fgetc(file)) != EOF) {
putchar(ch);
}
fclose(file);
return 0;
}
fread - Read Binary Data
#include <stdio.h>
typedef struct {
int id;
char name[50];
float salary;
} Employee;
int main(void) {
FILE *file = fopen("employees.dat", "rb");
if (file == NULL) return 1;
Employee emp;
// Read struct from binary file
size_t read = fread(&emp, sizeof(Employee), 1, file);
if (read == 1) {
printf("ID: %d, Name: %s, Salary: %.2f\n",
emp.id, emp.name, emp.salary);
}
fclose(file);
return 0;
}
22.5 File Position
ftell - Get Position
#include <stdio.h>
int main(void) {
FILE *file = fopen("data.txt", "r");
if (file == NULL) return 1;
// Get current position
long pos = ftell(file);
printf("Position: %ld\n", pos); // 0 (at start)
// Read some data
char buffer[10];
fgets(buffer, sizeof(buffer), file);
// Get new position
pos = ftell(file);
printf("Position after read: %ld\n", pos);
fclose(file);
return 0;
}
fseek - Set Position
#include <stdio.h>
int main(void) {
FILE *file = fopen("data.txt", "r");
if (file == NULL) return 1;
// Seek to end
fseek(file, 0, SEEK_END);
long size = ftell(file);
printf("File size: %ld bytes\n", size);
// Seek to beginning
fseek(file, 0, SEEK_SET);
// Seek forward 10 bytes
fseek(file, 10, SEEK_CUR);
fclose(file);
return 0;
}
Seek origins:
SEEK_SET- Beginning of fileSEEK_CUR- Current positionSEEK_END- End of file
rewind - Reset to Beginning
#include <stdio.h>
int main(void) {
FILE *file = fopen("data.txt", "r");
if (file == NULL) return 1;
// Read file
char buffer[100];
fgets(buffer, sizeof(buffer), file);
// Go back to start
rewind(file); // Same as fseek(file, 0, SEEK_SET)
// Read again
fgets(buffer, sizeof(buffer), file);
fclose(file);
return 0;
}
22.6 File Status
feof - Check End of File
#include <stdio.h>
int main(void) {
FILE *file = fopen("input.txt", "r");
if (file == NULL) return 1;
char ch;
while (!feof(file)) {
ch = fgetc(file);
if (ch != EOF) {
putchar(ch);
}
}
fclose(file);
return 0;
}
ferror - Check Errors
#include <stdio.h>
int main(void) {
FILE *file = fopen("output.txt", "w");
if (file == NULL) return 1;
fprintf(file, "Test\n");
if (ferror(file)) {
printf("Error writing to file!\n");
clearerr(file); // Clear error flag
}
fclose(file);
return 0;
}
File Existence
#include <stdio.h>
int fileExists(const char *filename) {
FILE *file = fopen(filename, "r");
if (file != NULL) {
fclose(file);
return 1;
}
return 0;
}
int main(void) {
if (fileExists("config.txt")) {
printf("Config file found!\n");
} else {
printf("Config file not found!\n");
}
return 0;
}
22.7 Practical Examples
Copy File
#include <stdio.h>
int copyFile(const char *src, const char *dest) {
FILE *source = fopen(src, "rb");
if (source == NULL) return 0;
FILE *target = fopen(dest, "wb");
if (target == NULL) {
fclose(source);
return 0;
}
// Copy buffer by buffer
char buffer[1024];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), source)) > 0) {
fwrite(buffer, 1, bytes, target);
}
fclose(source);
fclose(target);
return 1;
}
int main(void) {
if (copyFile("input.txt", "output.txt")) {
printf("File copied successfully!\n");
}
return 0;
}
Count Lines in File
#include <stdio.h>
int countLines(const char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL) return -1;
int lines = 0;
int ch;
while ((ch = fgetc(file)) != EOF) {
if (ch == '\n') {
lines++;
}
}
fclose(file);
return lines;
}
int main(void) {
int lines = countLines("input.txt");
printf("Lines: %d\n", lines);
return 0;
}
Read Entire File
#include <stdio.h>
#include <stdlib.h>
char* readFile(const char *filename, size_t *size) {
FILE *file = fopen(filename, "rb");
if (file == NULL) return NULL;
// Get file size
fseek(file, 0, SEEK_END);
long filesize = ftell(file);
rewind(file);
// Allocate buffer
char *buffer = (char*)malloc(filesize + 1);
if (buffer == NULL) {
fclose(file);
return NULL;
}
// Read entire file
size_t read = fread(buffer, 1, filesize, file);
buffer[read] = '\0'; // Null terminate
if (size != NULL) {
*size = read;
}
fclose(file);
return buffer;
}
int main(void) {
size_t size;
char *content = readFile("input.txt", &size);
if (content != NULL) {
printf("Content (%zu bytes):\n%s\n", size, content);
free(content);
}
return 0;
}
22.8 Configuration File (Clay Example)
Save Clay UI Configuration
#include <stdio.h>
typedef struct {
float width;
float height;
int layoutDirection;
int padding;
} Clay_LayoutConfig;
int saveLayoutConfig(const char *filename, Clay_LayoutConfig *config) {
FILE *file = fopen(filename, "w");
if (file == NULL) return 0;
fprintf(file, "width=%.2f\n", config->width);
fprintf(file, "height=%.2f\n", config->height);
fprintf(file, "layoutDirection=%d\n", config->layoutDirection);
fprintf(file, "padding=%d\n", config->padding);
fclose(file);
return 1;
}
int loadLayoutConfig(const char *filename, Clay_LayoutConfig *config) {
FILE *file = fopen(filename, "r");
if (file == NULL) return 0;
fscanf(file, "width=%f\n", &config->width);
fscanf(file, "height=%f\n", &config->height);
fscanf(file, "layoutDirection=%d\n", &config->layoutDirection);
fscanf(file, "padding=%d\n", &config->padding);
fclose(file);
return 1;
}
int main(void) {
Clay_LayoutConfig config = {
.width = 800.0f,
.height = 600.0f,
.layoutDirection = 0,
.padding = 16
};
// Save config
saveLayoutConfig("layout.cfg", &config);
// Load config
Clay_LayoutConfig loaded = {0};
if (loadLayoutConfig("layout.cfg", &loaded)) {
printf("Loaded: %.0fx%.0f, dir=%d, pad=%d\n",
loaded.width, loaded.height,
loaded.layoutDirection, loaded.padding);
}
return 0;
}
22.9 Binary File Format
Save/Load Array
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int count;
float *values;
} FloatArray;
int saveFloatArray(const char *filename, FloatArray *arr) {
FILE *file = fopen(filename, "wb");
if (file == NULL) return 0;
// Write count
fwrite(&arr->count, sizeof(int), 1, file);
// Write values
fwrite(arr->values, sizeof(float), arr->count, file);
fclose(file);
return 1;
}
FloatArray* loadFloatArray(const char *filename) {
FILE *file = fopen(filename, "rb");
if (file == NULL) return NULL;
FloatArray *arr = (FloatArray*)malloc(sizeof(FloatArray));
// Read count
fread(&arr->count, sizeof(int), 1, file);
// Allocate and read values
arr->values = (float*)malloc(arr->count * sizeof(float));
fread(arr->values, sizeof(float), arr->count, file);
fclose(file);
return arr;
}
int main(void) {
// Create array
FloatArray arr;
arr.count = 5;
arr.values = (float*)malloc(5 * sizeof(float));
for (int i = 0; i < 5; i++) {
arr.values[i] = i * 1.5f;
}
// Save
saveFloatArray("data.bin", &arr);
// Load
FloatArray *loaded = loadFloatArray("data.bin");
if (loaded != NULL) {
printf("Loaded %d values:\n", loaded->count);
for (int i = 0; i < loaded->count; i++) {
printf("%.1f ", loaded->values[i]);
}
printf("\n");
free(loaded->values);
free(loaded);
}
free(arr.values);
return 0;
}
22.10 Error Handling
Robust File Operations
#include <stdio.h>
#include <errno.h>
#include <string.h>
typedef enum {
FILE_OK,
FILE_ERROR_OPEN,
FILE_ERROR_READ,
FILE_ERROR_WRITE
} FileError;
FileError writeData(const char *filename, const char *data) {
FILE *file = fopen(filename, "w");
if (file == NULL) {
printf("Open error: %s\n", strerror(errno));
return FILE_ERROR_OPEN;
}
if (fputs(data, file) == EOF) {
printf("Write error: %s\n", strerror(errno));
fclose(file);
return FILE_ERROR_WRITE;
}
fclose(file);
return FILE_OK;
}
int main(void) {
FileError err = writeData("output.txt", "Hello!\n");
if (err != FILE_OK) {
printf("Error code: %d\n", err);
}
return 0;
}
22.11 Temporary Files
#include <stdio.h>
int main(void) {
// Create temporary file
FILE *temp = tmpfile();
if (temp == NULL) {
printf("Error creating temp file!\n");
return 1;
}
// Use temp file
fprintf(temp, "Temporary data\n");
rewind(temp);
char buffer[100];
fgets(buffer, sizeof(buffer), temp);
printf("Read: %s", buffer);
// File automatically deleted on close
fclose(temp);
return 0;
}
22.12 Buffer Control
Set Buffer Mode
#include <stdio.h>
int main(void) {
FILE *file = fopen("output.txt", "w");
if (file == NULL) return 1;
// Disable buffering
setbuf(file, NULL);
// Or set custom buffer
char buffer[BUFSIZ];
setvbuf(file, buffer, _IOFBF, BUFSIZ); // Full buffering
// _IONBF = No buffering
// _IOLBF = Line buffering
// _IOFBF = Full buffering
fprintf(file, "Data\n");
// Force write buffer
fflush(file);
fclose(file);
return 0;
}
22.13 Key Concepts Learned
- ✅ Opening and closing files
- ✅ File modes (read, write, append, binary)
- ✅ Writing: fprintf, fputs, fputc, fwrite
- ✅ Reading: fscanf, fgets, fgetc, fread
- ✅ File position: ftell, fseek, rewind
- ✅ File status: feof, ferror
- ✅ Binary file operations
- ✅ Error handling
- ✅ Configuration files
- ✅ Buffer control
Practice Exercises
- Create a text editor that can save/load files
- Build a CSV parser and writer
- Implement a simple database using binary files
- Create a log file system with timestamps
- Write a file encryption/decryption program
- Build a file comparison utility (diff)
- Implement a config file parser (INI format)
- Create a file compression utility (run-length encoding)