Reading and Writing Files

Write a program that asks for your high score, then close it and run it again. The score is gone. Every variable a program makes lives in the computer's memory (RAM) only while the program is running — the moment it ends, all of that memory is handed back and wiped clean. That's fine for a quick calculation, but useless for anything you want to keep: a saved game, a high-score table, a register of pupils, a document you're writing.

The answer is a file. A file is a named lump of data stored on a disk (a hard drive, an SSD, a USB stick), and — crucially — it persists: it stays there after the program ends, after you close the app, even after you switch the computer off. Saving to a file is how a program remembers things between one run and the next.

This page is about how a program gets data into and out of those files.

The three steps: open → read/write → close

Whatever the language, working with a file almost always follows the same three-step dance. Think of it like a library book:

Here is what those steps look like in a real program. This is not runnable here — our practice sandbox has no disk to read from or write to — but this is genuinely how the code reads when it runs on a real computer:

// --- Reading a whole file (real program; not runnable here) --- const file = openFile("scores.txt", "read"); // 1. open, for reading const contents = file.readAll(); // 2. read the text out console.log(contents); file.close(); // 3. close it // --- Writing to a file --- const out = openFile("scores.txt", "write"); // 1. open, for writing out.writeLine("Priya, 95"); // 2. write a line of text out.writeLine("Tom, 88"); out.close(); // 3. close — NOW it is saved

The exact names differ between languages (Python uses open() and with; others use readAll or ReadLine), but the shape is always the same: open, then read or write, then close.

Text files, line by line

Most files you'll meet at this level are text files — plain lines of text, one under the next, exactly like the lines in this paragraph. Because the data is naturally arranged as lines, a program usually reads a text file one line at a time, dealing with each line before moving to the next. That's perfect for a list of names, a set of scores, or a log of events:

// Reading a text file line by line (real program; not runnable here) const file = openFile("register.txt", "read"); for (const line of file.readLines()) { // one loop pass per line in the file console.log("Present: " + line); } file.close();

Notice how neatly this mirrors a loop over an array: each line is like one element, and the loop body handles it. That's the key insight for the runnable demo below.

Model a file as an array of lines

Since our sandbox has no real disk, we'll do the honest next-best thing. When a program reads a text file, what it ends up with in memory is essentially an array of lines. So we can put that array in the code directly and process it exactly as we would after reading a real file. The only difference is where the lines came from — here we type them in; in a real program the line const lines = file.readLines() would fill this same array from disk. Everything after that is identical.

Run this — it counts the lines in our "file", just like reading a register:

// In a real program: const lines = openFile("register.txt","read").readLines(); // Here we stand in for that array of lines the file would have given us: const lines: string[] = ["Amara", "Ben", "Chen", "Dara", "Eshan"]; let count: number = 0; for (const line of lines) { // process each "line", exactly as after a real read count = count + 1; } console.log("The file has " + count + " lines."); console.log("(That's just lines.length = " + lines.length + ".)");

Processing the lines: longest line, and totals

Once the file's lines are an array, every array trick you know works on them. Here we hunt for the longest line — the "keep the best so far" pattern — which is just the sort of thing you might do to a file of names or of words:

const lines: string[] = ["cat", "elephant", "dog", "hippopotamus", "ant"]; let longest: string = lines[0]; // best guess so far: the first line for (const line of lines) { if (line.length > longest.length) { longest = line; // found a longer one — remember it } } console.log('The longest line is "' + longest + '" (' + longest.length + " characters).");

Files of numbers are just as common — a file of daily temperatures, or of sales figures. Each line holds a number as text, so we turn it into a real number with Number(...) and add it to a running total (an accumulator):

// Each line is a number stored as text, as it would be read from a file: const lines: string[] = ["12", "8", "15", "20", "5"]; let total: number = 0; for (const line of lines) { total = total + Number(line); // turn the text "12" into the number 12, then add } console.log("There are " + lines.length + " numbers."); console.log("Their total is " + total + "."); console.log("Their average is " + (total / lines.length) + ".");

In a real program you'd read those lines from a file at the top and the loop would be unchanged. Learning to think of a file as "an array of lines I loop over" carries you a very long way.

Appending: adding without erasing

There are two ways to open a file for writing, and the difference matters enormously:

Append is exactly what you want for a growing record — a log file, a high-score table, a diary — where each run should add to the history, not replace it:

// Append one line to the end, keeping everything already saved const log = openFile("scores.txt", "append"); // note: "append", not "write" log.writeLine("Zoe, 99"); // added AFTER the existing lines log.close();

In our array-of-lines model, appending a line is simply lines.push(...) — adding a new element on the end, leaving the rest untouched:

const lines: string[] = ["Priya, 95", "Tom, 88"]; // what the file already holds console.log("Before:", lines); lines.push("Zoe, 99"); // append: add to the end, erase nothing console.log("After: ", lines); console.log("The file now has " + lines.length + " lines.");

Two classic file mistakes cost people real data — learn them now.

1. Write mode overwrites the whole file. Opening a file in write mode wipes everything already in it before you type a single character. If you meant to add a score but opened for writing, you've just deleted the entire high-score table:

// BUG: this destroys the existing scores! const out = openFile("scores.txt", "write"); // file is emptied the moment it opens out.writeLine("Zoe, 99"); // now this is the ONLY line left out.close();

If you want to keep the old data and add to it, open in append mode instead.

2. Forgetting to close the file. Your writes often sit in a temporary buffer in memory and are only truly saved to disk when the file is closed. Forget the close() and your carefully written lines may never reach the disk at all — the program looks like it worked, but the file is empty or half-written. Always close every file you open (many languages give you an automatic way to guarantee this, like Python's with block).