Data Persistence Through File Operations
Program data stored in memory is lost when the application terminates. To preserve information between sessions, file storage mechanisms are essential.
File Classification
Program vs Data Files
Software projects involve two primary file categories:
Program Files encompass:
- Source code files (.c extension)
- Compiled object files (.obj in Windows)
- Executable binaries (.exe in Windows)
Data Files contain runtime information that programs read or write during execution, distinct from executable code.
File Identification
Each file requires a unique identifier consisting of:
- Directory path
- Base filename
- Extension
Example: c:\projects\sample.txt
Text vs Binary Storage Formats
Data orgenization determines file classification:
Binary Files store raw memory representations without conversion.
Text Files encode data using ASCII characters, requiring transformation before storage.
Numeric values demonstrate the difference:
- Integer 10000 as ASCII text requires 5 bytes (one per digit)
- Same integer in binary format uses only 4 bytes
#include <stdio.h>
int main() {
int value = 10000;
FILE* output = fopen("example.dat", "wb");
fwrite(&value, sizeof(int), 1, output);
fclose(output);
return 0;
}
Stream Management and File Pointers
Standard Streams
C programs automatically initialize three streams:
stdinfor kyeboard input (scanf source)stdoutfor display output (printf destination)stderrfor error messages
These streams use FILE* type variables for internal management.
File Pointer Structure
The FILE structure maintains file state information including:
- Current position
- Buffer status
- File attributes
struct file_control {
char* buffer_ptr;
int available_chars;
char* base_address;
int flags;
int file_descriptor;
int char_buffer;
int buffer_size;
char* temp_filename;
};
typedef struct file_control FILE;
Opening and Closing Files
ANSI C provides standardized functions:
FILE* fopen(const char* filename, const char* mode);
int fclose(FILE* stream);
Available modes include:
"r"Read-only"w"Write (truncates existing)"a"Append"rb"Binary read"wb"Binary write
int main() {
FILE* data_file = fopen("records.txt", "w");
if (data_file == NULL) {
perror("File creation failed");
return 1;
}
fclose(data_file);
data_file = NULL;
return 0;
}
Sequential File Access Methods
Character Operatoins
Writing Characters
#include <stdio.h>
int main() {
FILE* target = fopen("alphabet.txt", "w");
if (target == NULL) {
perror("Opening failed");
return 1;
}
for (int idx = 0; idx < 26; idx++) {
fputc('a' + idx, target);
}
fclose(target);
target = NULL;
return 0;
}
Reading Characters
int main() {
FILE* source = fopen("alphabet.txt", "r");
if (source == NULL) {
perror("Opening failed");
return 1;
}
int character;
while ((character = fgetc(source)) != EOF) {
putchar(character);
}
fclose(source);
source = NULL;
return 0;
}
String Operations
Writing Lines
int main() {
FILE* document = fopen("lines.txt", "w");
if (document == NULL) {
perror("Opening failed");
return 1;
}
fputs("First line\n", document);
fputs("Second line\n", document);
fclose(document);
document = NULL;
return 0;
}
Reading Lines
int main() {
FILE* input = fopen("lines.txt", "r");
if (input == NULL) {
perror("Opening failed");
return 1;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), input) != NULL) {
printf("%s", buffer);
}
fclose(input);
input = NULL;
return 0;
}
Formatted Operations
Structured Data Writing
#include <stdio.h>
struct student_record {
char full_name[30];
int academic_year;
float gpa;
};
int main() {
struct student_record student = {"John Smith", 2, 3.75f};
FILE* records = fopen("students.txt", "w");
if (records == NULL) {
perror("Opening failed");
return 1;
}
fprintf(records, "%s %d %.2f",
student.full_name,
student.academic_year,
student.gpa);
fclose(records);
records = NULL;
return 0;
}
Structured Data Reading
int main() {
struct student_record retrieved = {0};
FILE* records = fopen("students.txt", "r");
if (records == NULL) {
perror("Opening failed");
return 1;
}
fscanf(records, "%s %d %f",
retrieved.full_name,
&retrieved.academic_year,
&retrieved.gpa);
fclose(records);
records = NULL;
return 0;
}
Binary Operations
Binary Writing
int main() {
struct student_record student = {"Alice Johnson", 3, 3.9f};
FILE* binary_file = fopen("student_data.bin", "wb");
if (binary_file == NULL) {
perror("Opening failed");
return 1;
}
fwrite(&student, sizeof(student), 1, binary_file);
fclose(binary_file);
binary_file = NULL;
return 0;
}
Binary Reading
int main() {
struct student_record loaded = {0};
FILE* binary_file = fopen("student_data.bin", "rb");
if (binary_file == NULL) {
perror("Opening failed");
return 1;
}
fread(&loaded, sizeof(loaded), 1, binary_file);
printf("%s %d %.1f\n",
loaded.full_name,
loaded.academic_year,
loaded.gpa);
fclose(binary_file);
binary_file = NULL;
return 0;
}
String Formatting Functions
Data to String Conversion
int main() {
struct student_record person = {"Bob Wilson", 1, 3.2f};
char formatted[100] = {0};
sprintf(formatted, "%s|%d|%.1f",
person.full_name,
person.academic_year,
person.gpa);
printf("%s\n", formatted);
return 0;
}
String to Data Conversion
int main() {
struct student_record parsed = {0};
char source[] = "Carol Brown|4|3.8";
sscanf(source, "%[^|]|%d|%f",
parsed.full_name,
&parsed.academic_year,
&parsed.gpa);
return 0;
}
Random Access Operations
Position Control
#include <stdio.h>
int main() {
FILE* file_handle = fopen("sample.txt", "r");
if (file_handle == NULL) {
perror("Opening failed");
return 1;
}
// Read first four characters
for (int i = 0; i < 4; i++) {
putchar(fgetc(file_handle));
}
// Move to position relative to end
fseek(file_handle, -6, SEEK_END);
putchar(fgetc(file_handle));
fclose(file_handle);
file_handle = NULL;
return 0;
}
Position Tracking
int main() {
FILE* tracker = fopen("sample.txt", "r");
if (tracker == NULL) {
perror("Opening failed");
return 1;
}
// Advance cursor
for (int i = 0; i < 4; i++) {
fgetc(tracker);
}
long position = ftell(tracker);
printf("Current offset: %ld\n", position);
fclose(tracker);
tracker = NULL;
return 0;
}
Reset Position
int main() {
FILE* reset_file = fopen("sample.txt", "r");
if (reset_file == NULL) {
perror("Opening failed");
return 1;
}
// Read initial characters
for (int i = 0; i < 4; i++) {
putchar(fgetc(reset_file));
}
// Return to beginning
rewind(reset_file);
putchar(fgetc(reset_file));
fclose(reset_file);
reset_file = NULL;
return 0;
}
End-of-File Detection
Text File Reading
#include <stdio.h>
#include <stdlib.h>
int main() {
int ch;
FILE* input_file = fopen("content.txt", "r");
if (!input_file) {
perror("Opening failed");
return EXIT_FAILURE;
}
while ((ch = fgetc(input_file)) != EOF) {
putchar(ch);
}
if (ferror(input_file)) {
puts("Read error occurred");
} else if (feof(input_file)) {
puts("End of file reached");
}
fclose(input_file);
input_file = NULL;
return 0;
}
Binary File Reading
int main() {
double original[] = {1.0, 2.0, 3.0, 4.0, 5.0};
FILE* binary_data = fopen("numbers.bin", "wb");
fwrite(original, sizeof(double), 5, binary_data);
fclose(binary_data);
double retrieved[5];
binary_data = fopen("numbers.bin", "rb");
size_t elements_read = fread(retrieved, sizeof(double), 5, binary_data);
if (elements_read == 5) {
for (int i = 0; i < 5; i++) {
printf("%.1f ", retrieved[i]);
}
} else {
if (feof(binary_data)) {
printf("Unexpected end of file\n");
} else if (ferror(binary_data)) {
perror("Read error");
}
}
fclose(binary_data);
binary_data = NULL;
return 0;
}
Buffer Management
The standard library uses memory buffers to optimize file I/O operations. Data moves between:
- Application memory
- System buffer
- Storage device
#include <windows.h>
int main() {
FILE* buffered_file = fopen("delayed.txt", "w");
fputs("buffer test", buffered_file);
printf("Data written to buffer - file empty\n");
Sleep(5000);
printf("Flushing buffer\n");
fflush(buffered_file);
printf("Data now visible in file\n");
Sleep(5000);
fclose(buffered_file);
buffered_file = NULL;
return 0;
}