I/O Operations in Dart
Learn console output, reading user input, file reading and writing, I/O error handling, and formatted output in Dart with Docker-ready examples
Input and output are how a program talks to the outside world — printing to the console, reading what a user types, and persisting data to files. In Hello World you met print(), but Dart’s I/O story goes much deeper through the dart:io library.
Dart is a multi-paradigm language with sound null safety, and both traits shape how you do I/O. The dart:io library gives you synchronous methods (great for scripts and learning) and asynchronous, Future-based methods (great for servers and apps that must stay responsive). Because reading a line of input might return null at end-of-stream, null safety forces you to handle the “nothing was read” case explicitly — the compiler won’t let you forget.
In this tutorial you’ll learn how to write to standard output and standard error, read text typed by a user, write and read files, handle I/O errors gracefully, and produce cleanly formatted output. Every example runs on the command line with the official dart:stable Docker image.
Note:
print()and string interpolation come fromdart:coreand need no import. Everything involvingstdout,stdin, andFilerequiresimport 'dart:io';.
Console Output Beyond print()
print() is convenient, but dart:io exposes the underlying stdout and stderr streams for finer control — writing without a trailing newline, joining collections, and separating normal output from error output.
Create a file named io_output.dart:
| |
Using stdout directly lets you build output piece by piece, while stderr keeps diagnostics out of your program’s real results — important when output is piped into another command.
Reading User Input
To read a line typed by the user, call stdin.readLineSync(). It returns a String? — nullable, because it yields null at end-of-input. Null safety means you must decide what happens when nothing is read.
Create a file named io_input.dart:
| |
The ?? (null-coalescing) operator is doing the heavy lifting: ageInput ?? '0' guarantees int.parse receives a non-null string, and name ?? 'stranger' guarantees a friendly greeting even at end-of-input.
Writing and Reading Files
File access goes through the File class. The ...Sync methods block until the operation completes, which keeps command-line examples simple and linear. writeAsStringSync creates (or overwrites) a file; passing FileMode.append adds to it instead.
Create a file named io_files.dart:
| |
readAsStringSync gives you the raw contents; readAsLinesSync splits on line boundaries and hands back a List<String>, which is perfect when you want to process a file line by line.
Handling I/O Errors
File operations can fail — a path may not exist, or you may lack permission. Reading a missing file throws a PathNotFoundException (a FileSystemException subtype). Wrap risky calls in try/catch, or check first with existsSync().
Create a file named io_errors.dart:
| |
The on PathNotFoundException clause catches the specific error, while the bare catch clause acts as a safety net. Checking existsSync() first is a good defensive habit when a missing file is an ordinary, expected situation rather than a true error.
Formatted Output
Dart formats output through methods on the values themselves rather than a printf-style format string. toStringAsFixed controls decimal places, padLeft/padRight align columns, and toRadixString converts numbers to other bases.
Create a file named io_format.dart:
| |
Because formatting lives on the values, you compose it naturally inside string interpolation — no separate format-string mini-language to memorize.
Running with Docker
| |
The -i flag on the input example keeps STDIN open so the piped values reach stdin.readLineSync().
Expected Output
Running io_output.dart:
Standard output with print()
No newline here... same line!
Written with writeln()
This goes to standard error
a-b-c
Running io_input.dart with Alice and 30 piped in:
What is your name? How old are you? Hello, Alice!
Next year you will be 31.
Running io_files.dart:
--- File contents ---
First line
Second line
Third line
The file has 3 lines.
File deleted: true
Running io_errors.dart:
Could not read file: does_not_exist.txt
File does not exist, skipping read.
Running io_format.dart:
Pi to 2 places: 3.14
Apple | 3
Banana | 12
Cherry | 150
Hex: 2a
Binary: 101010
Padded: 000042
Key Concepts
dart:iois required for real I/O —print()works out of the box, butstdout,stdin, andFileall needimport 'dart:io';.stdoutvsstderr— write results tostdoutand diagnostics tostderrso output can be piped cleanly into other tools.- Input is nullable —
stdin.readLineSync()returnsString?; sound null safety forces you to handle end-of-input, and the??operator makes supplying defaults concise. - Sync vs async — the
...Syncmethods block and keep scripts linear; production servers use theFuture-based versions withawaitto stay responsive. FileMode.append— controls whether a write overwrites or appends; the default replaces the file’s contents.- Specific exceptions — catch
PathNotFoundException(aFileSystemException) for missing files, and preferexistsSync()when a missing file is an expected, ordinary case. - Formatting lives on values —
toStringAsFixed,padLeft/padRight, andtoRadixStringcompose naturally inside string interpolation instead of aprintfformat string.
Comments
Loading comments...
Leave a Comment