Reading and Writing Files in Dart
Treat files as either a single string for simple cases or a stream of data for large ones. Use `dart:io` for saving user settings or processing logs. The main footgun is using synchronous methods like `readAsStringSync`, which can freeze your app.
WHY IT EXISTS: Apps often need to persist data beyond their runtime—saving user preferences, caching data, or logging events. The dart:io library provides a standard, cross-platform API to interact with the file system directly, making these tasks possible in Dart and Flutter.
THE MENTAL MODEL: Think of a File object not as the file itself, but as a remote control for a file on your disk. You create this remote by giving it a path (File('my_data.txt')). Then, you use its buttons—methods like readAsString() or writeAsString()—to perform operations on the actual file.
HOW IT WORKS: The File class offers two main approaches for I/O operations. First, convenience methods like readAsString() or writeAsString('content'). These are great for small configuration files and return a Future, so you must await the result. Second, streams. For large files, use openRead() to get a Stream of bytes or openWrite() to get an IOSink. Streams prevent loading a huge file into memory all at once and allow you to process data in chunks.
WHEN TO USE IT: Use convenience methods like readAsString() for small, simple files, like a user's theme preference in a JSON file. Use streams (openRead()) when dealing with files of unknown or potentially large size, like user-uploaded videos or extensive log files. This prevents your app from crashing due to high memory usage.
WHEN NOT TO USE IT: Avoid using the synchronous versions of methods (e.g., readAsStringSync()) in any performance-critical code, especially in a Flutter app's UI thread. They block all other operations until the file I/O is complete, leading to a frozen UI. For simple key-value storage, a package like shared_preferences might be a simpler abstraction than direct file I/O.
ONE CANONICAL EXAMPLE: To write text to a file and then read it back, you can use the asynchronous convenience methods. This pattern is common for saving and loading simple state. import 'dart:io'; void main() async { final file = File('log.txt'); // Write to the file await file.writeAsString('Hello, Dart!'); // Read from the file if (await file.exists()) { final contents = await file.readAsString(); print(contents); // Prints "Hello, Dart!" } } This example first creates a File object, writes a string to it, and then reads the entire content back. Each operation is asynchronous and uses await.
Read the original → api.dart.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.