Skip to content
AgileLogics
5 min read

Working with Files

Prerequisites: Futures and async/await

The dart:io library reads and writes files in command-line programs and servers. (Flutter apps use the same API, together with the path_provider package to find the right folder on each device. dart:io isn't available on the web.)

Reading and writing text

import 'dart:io';

Future<void> main() async {
  final file = File('${Directory.systemTemp.path}/notes.txt');

  await file.writeAsString('First line\nSecond line\n');
  await file.writeAsString('Third line\n', mode: FileMode.append);

  final text = await file.readAsString();
  print(text.trim());

  final lines = await file.readAsLines();
  print(lines.length);
  print(await file.exists());

  await file.delete();
  print(await file.exists());
}
First line
Second line
Third line
3
true
false
  • File operations return futures, so await them. (Synchronous versions such as readAsStringSync exist for simple scripts.)
  • FileMode.append adds to the end instead of replacing.

Large files: streaming lines

readAsString loads the whole file into memory. For big files, read it as a stream of lines:

import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  final log = File('${Directory.systemTemp.path}/app.log');
  await log.writeAsString('INFO start\nERROR disk full\nINFO retry\nERROR timeout\n');

  final errors = <String>[];
  await for (final line in log.openRead().transform(utf8.decoder).transform(const LineSplitter())) {
    if (line.startsWith('ERROR')) errors.add(line.substring(6));
  }
  print(errors);
  await log.delete();
}
[disk full, timeout]

await for processes each line as it arrives — streams are covered in depth in Level 3.

Folders

import 'dart:io';

Future<void> main() async {
  final dir = Directory('${Directory.systemTemp.path}/dart_demo');
  await dir.create(recursive: true);
  await File('${dir.path}/a.txt').writeAsString('a');
  await File('${dir.path}/b.md').writeAsString('b');

  final names = await dir.list().map((e) => e.uri.pathSegments.last).toList();
  print(names..sort());
  await dir.delete(recursive: true);
}
[a.txt, b.md]

The path package (package:path) builds and splits paths correctly on every operating system.

Common mistakes

  • Reading a missing file throws a PathNotFoundException (a FileSystemException). Check exists() or catch it.
  • Relative paths are relative to where the program was started, not to the source file.