I/O Operations in Nim
Learn console input and output, file reading and writing, formatted output, and I/O error handling in Nim with Docker-ready examples
Input and output are how a program talks to the outside world: printing results, reading what the user types, and persisting data to files. You have already met echo in the Hello World tutorial, but Nim’s standard library offers far more control than that single procedure suggests.
Nim is a multi-paradigm systems language, and its I/O reflects that heritage. Console and file operations are ordinary procedures that work on File objects, giving you C-like control while keeping Python-like readability. Because these operations touch the outside world, they are not pure — this is where Nim’s compile-time effect system matters. You cannot call readFile from a procedure marked func (which is shorthand for {.noSideEffect.}), because the compiler tracks that I/O has side effects.
In this tutorial you will learn how to write to the console with fine-grained control, read input from standard input, read and write files, format output cleanly with std/strformat, and handle I/O failures with try/except. Every example runs unchanged inside the official nimlang/nim:alpine Docker image.
Console Output Beyond echo
echo is convenient but always appends a newline and always joins its arguments. When you need precise control over spacing and line breaks, reach for the stdout file handle directly.
Create a file named io_output.nim:
| |
Key points:
echoconverts every argument with$and separates nothing automatically — add spaces yourself.stdout.writewrites raw text with no newline, ideal for prompts.stdout.writeLineiswriteplus a trailing newline.
Expected Output
echo adds a newline and can join args: 42 true
No newline here... continued on same line
writeLine adds its own newline
abc
Reading Input from the Console
To read what a user types, use readLine(stdin). Input always arrives as a string, so convert it with helpers from std/strutils such as parseInt.
Create a file named io_input.nim:
| |
Because this program waits for interactive input, you can feed it values through a pipe so the run is reproducible. In Docker, pipe two lines into the program’s standard input:
| |
Expected Output
What is your name? What is your favorite number? Hello, Ada!
Your number doubled is 42
The two prompts appear back-to-back because the piped input is consumed instantly rather than typed by a human. Run it interactively (without the pipe) and you will see each prompt pause for your answer.
Reading and Writing Files
Nim offers both whole-file convenience procedures and line-oriented file handles. writeFile and readFile handle an entire file in one call, while open gives you a File you can append to or iterate over. Always close a file handle you open explicitly.
Create a file named io_files.nim:
| |
Key points:
writeFile/readFileare the simplest way to move an entire file in or out of memory.open(path, fmAppend)opens for appending; other modes includefmRead,fmWrite, andfmReadWrite.lines(path)is an iterator that yields each line without its terminating newline — perfect for processing text files.
Expected Output
--- Full contents ---
First line
Second line
Third line (appended)
--- Line by line ---
> First line
> Second line
> Third line (appended)
The blank line after the full contents comes from the file’s own trailing newline plus the newline echo adds.
Formatted Output with strformat
For readable, aligned, and precisely formatted output, the std/strformat module provides fmt string interpolation — similar to Python’s f-strings but resolved at compile time.
Create a file named io_format.nim:
| |
Key points:
fmt"..."interpolates any expression inside{}and is evaluated when the program compiles.{value:<12}and{value:>4}control alignment and field width.{pi:.2f},{count:x}, and{count:b}apply precision, hex, and binary format specifiers.
Expected Output
Language: Nim, version 2.2
Widgets | 7
Pi to 2 dp: 3.14
7 in hex = 7, in binary = 111
Handling I/O Errors
File operations can fail — a path may not exist, or you may lack permission. Nim signals these problems by raising IOError, which you catch with try/except. This keeps error handling explicit and lets a program recover gracefully instead of crashing.
Create a file named io_errors.nim:
| |
Key points:
try/except IOError as ecatches the failure and exposes the message viae.msg.resultis Nim’s implicit return variable — assigning to it sets the procedure’s return value.strip()fromstd/strutilsremoves the trailing newline before printing.
Expected Output
Could not read does_not_exist.txt: cannot open: does_not_exist.txt
Length of missing file contents: 0
Config: setting=on
Running with Docker
All five programs run with the same command pattern — swap in the filename you want to execute. The -r flag compiles to C and runs the resulting binary immediately.
| |
For the interactive input example, add -i and pipe the answers in so the program has something to read:
| |
The volume mount (-v $(pwd):/app) is what lets file examples like io_files.nim write notes.txt and config.txt back to your current directory, where you can inspect them after the container exits.
Key Concepts
echovsstdout.write—echoalways adds a newline and joins arguments;stdout.writegives you raw, newline-free control ideal for prompts.- Input is always text —
readLine(stdin)returns a string; convert it withparseInt,parseFloat, and friends fromstd/strutils. - Two file styles — use
readFile/writeFilefor whole files, oropen/closewith aFilehandle when you need appending or line-by-line iteration vialines(). - File modes matter —
fmRead,fmWrite,fmAppend, andfmReadWritedecide what an opened file can do. std/strformat— thefmtmacro provides compile-time string interpolation with alignment, precision, hex, and binary specifiers.- I/O errors are exceptions — wrap risky file operations in
try/except IOErrorand read the cause frome.msg. - Effect tracking — because I/O has side effects, these procedures cannot be called from a
func; Nim’s compiler enforces the pure/impure boundary for you. - Always close what you open — explicit
openhandles should be paired withcloseto flush buffers and release the file.
Running Today
All examples can be run using Docker:
docker pull nimlang/nim:alpine
Comments
Loading comments...
Leave a Comment