tezvyn:

Reading and Writing Files in Dart

AI-drafted, machine-checkedSource: api.dart.devbeginner

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.