|$ curl https://forge-ai.dev/api/markdown?path=docs/c/file-io
$cat docs/c-—-file-i/o.md
updated Recently·40 min read·published

C — File I/O

CFile I/OFilesIntermediateIntermediate🎯Free Tools
Introduction

File I/O is how C programs persist data and communicate with the outside world. The standard library provides a buffered, portable interface through FILE streams. This page covers every major I/O function, from character-level reads to binary record databases.

FILE Type & File Pointers

FILE is an opaque type defined by the standard library. It encapsulates the file descriptor, buffering state, error flags, and EOF indicator. You always work withFILE* pointers:

hello-file.c
C
1#include <stdio.h>
2
3int main(void) {
4 FILE *fp = fopen("example.txt", "w");
5 if (!fp) {
6 perror("fopen");
7 return 1;
8 }
9
10 fprintf(fp, "Hello, file!\n");
11 fclose(fp);
12 return 0;
13}

info

Always check the return value of fopen. A NULL return means the file could not be opened (permissions, missing directory, too many open files).
fopen: Opening Files & Modes

fopen(filename, mode) opens a stream. The mode string controls read/write access and positioning:

ModeDescriptionFile Must ExistPosition
"r"Read onlyYesBeginning
"w"Write only, truncatesNo (creates)Beginning
"a"Append onlyNo (creates)End
"rb"Binary readYesBeginning
"wb"Binary write, truncatesNo (creates)Beginning
"r+"Read + writeYesBeginning
"w+"Read + write, truncatesNo (creates)Beginning
"a+"Read + appendNo (creates)End (writes always append)
modes.c
C
1FILE *fp;
2
3fp = fopen("data.txt", "r"); /* read existing file */
4if (!fp) { /* handle error */ }
5
6fp = fopen("output.txt", "w"); /* create/overwrite */
7if (!fp) { /* handle error */ }
8
9fp = fopen("log.txt", "a"); /* append to end */
10if (!fp) { /* handle error */ }
11
12fp = fopen("image.bin", "rb"); /* binary read */
13if (!fp) { /* handle error */ }
14
15fp = fopen("data.bin", "wb"); /* binary write */
16if (!fp) { /* handle error */ }
fclose: Closing & Flushing

fclose flushes any buffered output and releases the stream. Failing to close files leaks file descriptors. For program exit, the OS reclaims them, but in long-running programs this is a resource leak:

fclose.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4int write_data(const char *path) {
5 FILE *fp = fopen(path, "w");
6 if (!fp) return -1;
7
8 for (int i = 0; i < 1000; i++) {
9 fprintf(fp, "Line %d\n", i);
10 }
11
12 if (fclose(fp) != 0) {
13 perror("fclose");
14 return -1;
15 }
16 return 0;
17}
18
19int main(void) {
20 if (write_data("output.txt") != 0) {
21 fprintf(stderr, "Failed to write data\n");
22 return 1;
23 }
24 printf("Done.\n");
25 return 0;
26}

warning

fclose can fail if flushing pending writes encounters an error (disk full, NFS disconnect). Always check its return value in production code.
Error Checking & errno

The errno global (from<errno.h>) is set by failing system calls. Pair it with perroror strerror for diagnostics:

error-check.c
C
1#include <stdio.h>
2#include <errno.h>
3#include <string.h>
4
5void open_file(const char *path) {
6 FILE *fp = fopen(path, "r");
7 if (!fp) {
8 fprintf(stderr, "Cannot open '%s': %s\n",
9 path, strerror(errno));
10 return;
11 }
12 printf("Opened %s successfully\n", path);
13 fclose(fp);
14}
15
16int main(void) {
17 open_file("nonexistent.txt");
18 /* prints: Cannot open 'nonexistent.txt': No such file or directory */
19 return 0;
20}
Character I/O: fgetc, fputc, fgets, fputs

These are the low-level building blocks. Every other I/O function is built on top of them. They handle EOF and errors through return values:

char-io.c
C
1#include <stdio.h>
2#include <ctype.h>
3
4/* Count characters, words, and lines */
5void count_file(const char *path) {
6 FILE *fp = fopen(path, "r");
7 if (!fp) { perror("fopen"); return; }
8
9 int ch;
10 long chars = 0, words = 0, lines = 0;
11 int in_word = 0;
12
13 while ((ch = fgetc(fp)) != EOF) {
14 chars++;
15 if (ch == '\n') lines++;
16 if (isspace(ch)) {
17 in_word = 0;
18 } else if (!in_word) {
19 in_word = 1;
20 words++;
21 }
22 }
23
24 printf("%ld chars, %ld words, %ld lines\n", chars, words, lines);
25 fclose(fp);
26}
27
28/* Write a string character by character */
29void write_chars(FILE *fp, const char *s) {
30 while (*s) {
31 fputc(*s++, fp);
32 }
33}
34
35int main(void) {
36 /* Write test file */
37 FILE *fp = fopen("test.txt", "w");
38 write_chars(fp, "Hello\nWorld\nFoo Bar Baz\n");
39 fclose(fp);
40
41 count_file("test.txt");
42 return 0;
43}
Line-by-Line: fgets & fputs

fgets(buf, n, fp) reads up to n-1 characters or until a newline. It always null-terminates. This is the safest way to read text lines — unlikegets which was removed in C11:

fgets-fputs.c
C
1#include <stdio.h>
2#include <string.h>
3
4#define MAX_LINE 1024
5
6void copy_file(const char *src, const char *dst) {
7 FILE *in = fopen(src, "r");
8 FILE *out = fopen(dst, "w");
9 if (!in || !out) { perror("fopen"); return; }
10
11 char line[MAX_LINE];
12 while (fgets(line, sizeof(line), in) != NULL) {
13 fputs(line, out);
14 }
15
16 fclose(in);
17 fclose(out);
18}
19
20void print_numbered(const char *path) {
21 FILE *fp = fopen(path, "r");
22 if (!fp) { perror("fopen"); return; }
23
24 char line[MAX_LINE];
25 int lineno = 1;
26 while (fgets(line, sizeof(line), fp) != NULL) {
27 printf("%4d: %s", lineno++, line);
28 }
29
30 fclose(fp);
31}
32
33int main(void) {
34 /* Create a test file */
35 FILE *fp = fopen("source.txt", "w");
36 fprintf(fp, "first line\nsecond line\nthird line\n");
37 fclose(fp);
38
39 copy_file("source.txt", "copy.txt");
40 print_numbered("source.txt");
41 return 0;
42}
Formatted I/O: fprintf & fscanf

fprintf andfscanf are the file-based equivalents of printf andscanf. They support the same format specifiers:

records.c
C
1#include <stdio.h>
2
3struct Record {
4 int id;
5 char name[64];
6 double value;
7};
8
9int save_records(const char *path, const struct Record *recs, int n) {
10 FILE *fp = fopen(path, "w");
11 if (!fp) return -1;
12
13 fprintf(fp, "%d\n", n);
14 for (int i = 0; i < n; i++) {
15 fprintf(fp, "%d,%s,%.2f\n", recs[i].id, recs[i].name, recs[i].value);
16 }
17
18 fclose(fp);
19 return 0;
20}
21
22int load_records(const char *path, struct Record *recs, int max) {
23 FILE *fp = fopen(path, "r");
24 if (!fp) return -1;
25
26 int n = 0;
27 fscanf(fp, "%d\n", &n);
28 if (n > max) n = max;
29
30 for (int i = 0; i < n; i++) {
31 fscanf(fp, "%d,%63[^,],%lf\n",
32 &recs[i].id, recs[i].name, &recs[i].value);
33 }
34
35 fclose(fp);
36 return n;
37}
38
39int main(void) {
40 struct Record data[] = {
41 { 1, "Alpha", 99.5 },
42 { 2, "Beta", 42.0 },
43 { 3, "Gamma", 7.25 },
44 };
45 int n = sizeof(data) / sizeof(data[0]);
46
47 save_records("records.csv", data, n);
48
49 struct Record loaded[10];
50 int count = load_records("records.csv", loaded, 10);
51
52 for (int i = 0; i < count; i++) {
53 printf("#%d %s = %.2f\n", loaded[i].id, loaded[i].name, loaded[i].value);
54 }
55 return 0;
56}
Binary I/O: fread & fwrite

For binary data, fread andfwrite transfer raw bytes. They are essential for image files, serialized structures, and any non-text format:

binary-io.c
C
1#include <stdio.h>
2#include <string.h>
3
4typedef struct {
5 char magic[4]; /* "BIN1" */
6 uint32_t version;
7 uint32_t count;
8} FileHeader;
9
10typedef struct {
11 uint32_t id;
12 double values[4];
13 char label[16];
14} DataPoint;
15
16int write_binary(const char *path, const DataPoint *pts, uint32_t n) {
17 FILE *fp = fopen(path, "wb");
18 if (!fp) return -1;
19
20 FileHeader hdr = { .magic = "BIN1", .version = 1, .count = n };
21 fwrite(&hdr, sizeof(hdr), 1, fp);
22 fwrite(pts, sizeof(DataPoint), n, fp);
23
24 fclose(fp);
25 return 0;
26}
27
28int read_binary(const char *path, DataPoint *pts, uint32_t max) {
29 FILE *fp = fopen(path, "rb");
30 if (!fp) return -1;
31
32 FileHeader hdr;
33 if (fread(&hdr, sizeof(hdr), 1, fp) != 1) {
34 fclose(fp);
35 return -1;
36 }
37
38 if (memcmp(hdr.magic, "BIN1", 4) != 0 || hdr.version != 1) {
39 fclose(fp);
40 return -1;
41 }
42
43 uint32_t to_read = hdr.count < max ? hdr.count : max;
44 size_t read = fread(pts, sizeof(DataPoint), to_read, fp);
45 fclose(fp);
46 return (int)read;
47}
48
49int main(void) {
50 DataPoint data[] = {
51 { .id = 1, .values = {1.0, 2.0, 3.0, 4.0}, .label = "first" },
52 { .id = 2, .values = {5.0, 6.0, 7.0, 8.0}, .label = "second" },
53 };
54
55 write_binary("data.bin", data, 2);
56
57 DataPoint loaded[10];
58 int n = read_binary("data.bin", loaded, 10);
59
60 for (int i = 0; i < n; i++) {
61 printf("#%u %s: [%.1f, %.1f, %.1f, %.1f]\n",
62 loaded[i].id, loaded[i].label,
63 loaded[i].values[0], loaded[i].values[1],
64 loaded[i].values[2], loaded[i].values[3]);
65 }
66 return 0;
67}

best practice

Always include a header with magic bytes and version numbers in binary files. This allows you to evolve the format without breaking old files.
Reading an Entire File

To read an entire file into memory, seek to the end to get the size, allocate, then read:

read-all.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4char *read_file(const char *path, long *out_size) {
5 FILE *fp = fopen(path, "rb");
6 if (!fp) return NULL;
7
8 fseek(fp, 0, SEEK_END);
9 long size = ftell(fp);
10 rewind(fp);
11
12 char *buf = malloc(size + 1);
13 if (!buf) { fclose(fp); return NULL; }
14
15 size_t read = fread(buf, 1, size, fp);
16 buf[read] = '\0';
17 fclose(fp);
18
19 if (out_size) *out_size = (long)read;
20 return buf;
21}
22
23int main(void) {
24 long size = 0;
25 char *content = read_file("test.txt", &size);
26 if (content) {
27 printf("Read %ld bytes:\n%s\n", size, content);
28 free(content);
29 }
30 return 0;
31}
File Positioning: fseek, ftell, rewind

These functions let you jump to arbitrary positions in a file — essential for random access, updating records in place, and parsing structured binary formats:

fseek.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4typedef struct {
5 int id;
6 char name[32];
7 double balance;
8} Account;
9
10int main(void) {
11 /* Create sample accounts */
12 FILE *fp = fopen("accounts.dat", "w+b");
13 Account accounts[] = {
14 { 101, "Alice", 1000.00 },
15 { 102, "Bob", 2500.50 },
16 { 103, "Carol", 750.25 },
17 };
18 fwrite(accounts, sizeof(Account), 3, fp);
19
20 /* Read account #102 (second record) */
21 fseek(fp, 1 * sizeof(Account), SEEK_SET);
22 Account acc;
23 fread(&acc, sizeof(Account), 1, fp);
24 printf("Read: %s balance=%.2f\n", acc.name, acc.balance);
25
26 /* Update Bob's balance */
27 acc.balance += 500.00;
28 fseek(fp, 1 * sizeof(Account), SEEK_SET);
29 fwrite(&acc, sizeof(Account), 1, fp);
30
31 /* Verify */
32 rewind(fp);
33 fseek(fp, 1 * sizeof(Account), SEEK_SET);
34 fread(&acc, sizeof(Account), 1, fp);
35 printf("Updated: %s balance=%.2f\n", acc.name, acc.balance);
36
37 fclose(fp);
38 return 0;
39}
FunctionDescription
fseek(fp, offset, whence)Move to absolute or relative position
ftell(fp)Return current position
rewind(fp)Move to beginning (calls fseek(0, SEEK_SET))
fgetpos(fp, pos)Save current position into fpos_t
fsetpos(fp, pos)Restore a previously saved position
Binary vs Text Mode
AspectText ModeBinary Mode
Line endingsTranslated (platform-specific)No translation
Use caseHuman-readable filesImages, structs, protocols
fseek reliabilityOnly ftell for positionExact byte offsets
Mode string"r", "w", "a""rb", "wb", "ab"
ConversionMay convert newlinesRaw bytes

warning

On Windows, text mode translates \\nto \\r\\n on write and back on read. This makes ftell unreliable for position tracking in text mode on Windows. Always use binary mode for random access.
File I/O for Structured Data

Writing and reading structs directly to files creates compact, fast-loading data formats. The key concerns are padding, endianness, and struct size across platforms:

packed-records.c
C
1#include <stdio.h>
2#include <string.h>
3
4typedef struct __attribute__((packed)) {
5 uint32_t id;
6 float x, y;
7 char label[12];
8} PackedRecord;
9
10void write_records(const char *path) {
11 FILE *fp = fopen(path, "wb");
12 PackedRecord recs[] = {
13 { 1, 1.0f, 2.0f, "alpha" },
14 { 2, 3.0f, 4.0f, "beta" },
15 { 3, 5.0f, 6.0f, "gamma" },
16 };
17 fwrite(recs, sizeof(PackedRecord), 3, fp);
18 fclose(fp);
19}
20
21void read_records(const char *path) {
22 FILE *fp = fopen(path, "rb");
23 PackedRecord rec;
24 while (fread(&rec, sizeof(PackedRecord), 1, fp) == 1) {
25 printf("#%u (%.1f, %.1f) %s\n", rec.id, rec.x, rec.y, rec.label);
26 }
27 fclose(fp);
28}
29
30int main(void) {
31 write_records("packed.dat");
32 read_records("packed.dat");
33 return 0;
34}
Temporary Files & File Management

The standard library provides functions for temporary files, file deletion, and renaming. These are essential for safe write patterns (write-to-temp, then atomic rename):

temp-files.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4void safe_write(const char *path, const char *data) {
5 /* Write to temp file first */
6 FILE *tmp = tmpfile();
7 if (!tmp) { perror("tmpfile"); return; }
8
9 fputs(data, tmp);
10
11 /* In production: copy tmp contents to path via rename() */
12 /* For this example, we just write directly */
13 FILE *fp = fopen(path, "w");
14 if (fp) {
15 rewind(tmp);
16 char buf[4096];
17 size_t n;
18 while ((n = fread(buf, 1, sizeof(buf), tmp)) > 0) {
19 fwrite(buf, 1, n, fp);
20 }
21 fclose(fp);
22 }
23}
24
25int main(void) {
26 safe_write("output.txt", "Safe content\n");
27
28 /* rename() for atomic replacement */
29 rename("output.txt.final", "output.txt");
30
31 /* remove() to delete a file */
32 remove("output.txt");
33
34 return 0;
35}
Standard Streams: stdin, stdout, stderr

Every C program starts with three open streams.freopen redirects a stream to a file — useful for logging or capturing user input:

freopen.c
C
1#include <stdio.h>
2
3int main(void) {
4 /* Redirect stdout to a log file */
5 FILE *log = freopen("app.log", "w", stdout);
6 if (!log) { perror("freopen"); return 1; }
7
8 printf("This goes to app.log\n");
9 printf("So does this\n");
10
11 /* Restore stdout */
12 freopen("/dev/tty", "w", stdout);
13 /* On Windows: freopen("CON", "w", stdout); */
14
15 printf("This goes to the terminal\n");
16
17 fclose(log);
18 return 0;
19}
EOF Detection & Error Handling

feof returns true after a read attempt fails at end-of-file. ferrorreturns true if any error occurred on the stream. The correct pattern for reading is to check the return value of the read function, notfeof:

feof-ferror.c
C
1#include <stdio.h>
2
3int process_file(const char *path) {
4 FILE *fp = fopen(path, "r");
5 if (!fp) return -1;
6
7 int ch;
8 while ((ch = fgetc(fp)) != EOF) {
9 /* process character */
10 }
11
12 if (ferror(fp)) {
13 fprintf(stderr, "Error reading %s\n", path);
14 fclose(fp);
15 return -1;
16 }
17
18 if (!feof(fp)) {
19 fprintf(stderr, "Unexpected end\n");
20 fclose(fp);
21 return -1;
22 }
23
24 fclose(fp);
25 return 0;
26}

warning

Never use while (!feof(fp)) as the loop condition. This reads one extra time past EOF becausefeof only returns trueafter a failed read.
Example: Word Counter
word-count.c
C
1#include <stdio.h>
2#include <ctype.h>
3
4typedef struct {
5 long chars;
6 long words;
7 long lines;
8} WordCount;
9
10WordCount count_file(const char *path) {
11 WordCount wc = { 0, 0, 0 };
12 FILE *fp = fopen(path, "r");
13 if (!fp) return wc;
14
15 int ch, in_word = 0;
16 while ((ch = fgetc(fp)) != EOF) {
17 wc.chars++;
18 if (ch == '\n') wc.lines++;
19 if (isspace(ch)) {
20 in_word = 0;
21 } else if (!in_word) {
22 in_word = 1;
23 wc.words++;
24 }
25 }
26
27 fclose(fp);
28 return wc;
29}
30
31int main(void) {
32 WordCount wc = count_file("article.txt");
33 printf("Chars: %ld, Words: %ld, Lines: %ld\n",
34 wc.chars, wc.words, wc.lines);
35 return 0;
36}
Example: CSV Parser
csv-parser.c
C
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4
5#define MAX_LINE 1024
6#define MAX_FIELDS 32
7
8typedef struct {
9 char *fields[MAX_FIELDS];
10 int field_count;
11} CSVRow;
12
13void free_csv_row(CSVRow *row) {
14 for (int i = 0; i < row->field_count; i++)
15 free(row->fields[i]);
16 row->field_count = 0;
17}
18
19int parse_csv_line(const char *line, CSVRow *row) {
20 row->field_count = 0;
21 const char *start = line;
22
23 while (*start && *start != '\n' && *start != '\r') {
24 if (*start == ',') {
25 start++;
26 continue;
27 }
28
29 const char *end = start;
30 while (*end && *end != ',' && *end != '\n' && *end != '\r')
31 end++;
32
33 size_t len = end - start;
34 row->fields[row->field_count] = malloc(len + 1);
35 memcpy(row->fields[row->field_count], start, len);
36 row->fields[row->field_count][len] = '\0';
37 row->field_count++;
38
39 start = end;
40 if (row->field_count >= MAX_FIELDS) break;
41 }
42 return row->field_count;
43}
44
45void process_csv(const char *path) {
46 FILE *fp = fopen(path, "r");
47 if (!fp) { perror("fopen"); return; }
48
49 char line[MAX_LINE];
50 int header_done = 0;
51
52 while (fgets(line, sizeof(line), fp)) {
53 CSVRow row = { 0 };
54 parse_csv_line(line, &row);
55
56 if (!header_done) {
57 printf("Headers: ");
58 for (int i = 0; i < row.field_count; i++)
59 printf("[%s] ", row.fields[i]);
60 printf("\n");
61 header_done = 1;
62 } else {
63 printf("Row: ");
64 for (int i = 0; i < row.field_count; i++)
65 printf("%s ", row.fields[i]);
66 printf("\n");
67 }
68
69 free_csv_row(&row);
70 }
71
72 fclose(fp);
73}
74
75int main(void) {
76 /* Create sample CSV */
77 FILE *fp = fopen("data.csv", "w");
78 fprintf(fp, "name,age,city\n");
79 fprintf(fp, "Alice,30,NYC\n");
80 fprintf(fp, "Bob,25,LA\n");
81 fprintf(fp, "Carol,35,Chicago\n");
82 fclose(fp);
83
84 process_csv("data.csv");
85 remove("data.csv");
86 return 0;
87}
Example: Binary File Copier
copier.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4#define COPY_BUF_SIZE (64 * 1024)
5
6int copy_file(const char *src, const char *dst) {
7 FILE *in = fopen(src, "rb");
8 FILE *out = fopen(dst, "wb");
9 if (!in || !out) {
10 perror("fopen");
11 if (in) fclose(in);
12 if (out) fclose(out);
13 return -1;
14 }
15
16 char buf[COPY_BUF_SIZE];
17 size_t n;
18 long total = 0;
19
20 while ((n = fread(buf, 1, COPY_BUF_SIZE, in)) > 0) {
21 size_t written = fwrite(buf, 1, n, out);
22 if (written != n) {
23 fprintf(stderr, "Write error after %ld bytes\n", total);
24 fclose(in);
25 fclose(out);
26 return -1;
27 }
28 total += (long)n;
29 }
30
31 if (ferror(in)) {
32 fprintf(stderr, "Read error\n");
33 fclose(in);
34 fclose(out);
35 return -1;
36 }
37
38 fclose(in);
39 fclose(out);
40 printf("Copied %ld bytes\n", total);
41 return 0;
42}
43
44int main(void) {
45 copy_file("source.bin", "dest.bin");
46 return 0;
47}
Security Considerations

File I/O introduces security risks. Path traversal, buffer overflows from untrusted file names, and denial-of-service through giant files must all be addressed:

safe-io.c
C
1#include <stdio.h>
2#include <string.h>
3#include <limits.h>
4
5/* Reject paths with traversal sequences */
6int is_safe_path(const char *path) {
7 if (strstr(path, "..")) return 0;
8 if (strstr(path, "//")) return 0;
9#ifdef _WIN32
10 if (strstr(path, "\\")) return 0;
11 if (path[1] == ':') return 0; /* absolute drive letter */
12#else
13 if (path[0] == '/') return 0; /* reject absolute paths */
14#endif
15 return 1;
16}
17
18/* Safe file read with size limit */
19char *safe_read(const char *path, long max_size) {
20 if (!is_safe_path(path)) {
21 fprintf(stderr, "Unsafe path: %s\n", path);
22 return NULL;
23 }
24
25 FILE *fp = fopen(path, "rb");
26 if (!fp) return NULL;
27
28 fseek(fp, 0, SEEK_END);
29 long size = ftell(fp);
30 rewind(fp);
31
32 if (size > max_size || size < 0) {
33 fclose(fp);
34 return NULL;
35 }
36
37 char *buf = malloc(size + 1);
38 if (!buf) { fclose(fp); return NULL; }
39
40 size_t n = fread(buf, 1, size, fp);
41 buf[n] = '\0';
42 fclose(fp);
43 return buf;
44}

warning

Never construct file paths from user input without sanitization. Always reject .. sequences and absolute paths. Limit file sizes before reading into memory.
Portable File I/O

Cross-platform file I/O must handle endianness, line endings, and struct padding differences. Use network byte order for binary data and always open binary files with"rb" / "wb":

portable.c
C
1#include <stdio.h>
2#include <stdint.h>
3
4/* Endian-safe read/write for portable binary files */
5uint32_t read_u32_be(FILE *fp) {
6 uint8_t buf[4];
7 if (fread(buf, 1, 4, fp) != 4) return 0;
8 return ((uint32_t)buf[0] << 24) |
9 ((uint32_t)buf[1] << 16) |
10 ((uint32_t)buf[2] << 8) |
11 ((uint32_t)buf[3]);
12}
13
14void write_u32_be(FILE *fp, uint32_t val) {
15 uint8_t buf[4];
16 buf[0] = (val >> 24) & 0xFF;
17 buf[1] = (val >> 16) & 0xFF;
18 buf[2] = (val >> 8) & 0xFF;
19 buf[3] = (val) & 0xFF;
20 fwrite(buf, 1, 4, fp);
21}
22
23int main(void) {
24 FILE *fp = fopen("portable.bin", "wb");
25 write_u32_be(fp, 0xDEADBEEF);
26 fclose(fp);
27
28 fp = fopen("portable.bin", "rb");
29 uint32_t val = read_u32_be(fp);
30 printf("Read: 0x%08X\n", val); /* 0xDEADBEEF on any platform */
31 fclose(fp);
32 return 0;
33}

info

For line-oriented files, always open in text mode and usefgets/fputs. The C library translates newlines to the platform convention.
$Blueprint — Engineering Documentation·Section ID: C-FILE-IO·Revision: 1.0