ZetCode

Dart write file

last modified May 30, 2026

In this article we show how to write to files in Dart language.

The dart:io package is used to do IO operations, including writing files. The File class contains methods for manipulating files and their contents.

Dart provides both synchronous and asynchronous methods for writing to files, such as writeAsStringSync and writeAsString.

The openWrite method creates a new IOSink for the file. It must be explicitly closed when no longer used, to flush buffered data and free system resources.

The FileMode enum controls how a file is opened for writing. The default FileMode.write truncates the file before writing, while FileMode.append adds data at the end of an existing file without erasing its contents. Other options include FileMode.writeOnly, which opens the file for writing only.

Note: methods that write a string or a list into a file in one go should not be used for large amounts of data. For large files, prefer the streaming IOSink API.

Dart writeAsStringSync

The writeAsStringSync method synchronously writes a string to a file. It opens the file, writes the string in the given encoding (UTF-8 by default), and closes the file. Because this call blocks the current isolate, it is best suited for short scripts or situations where the data is small.

main.dart
import 'dart:io';

void main() {
  final fname = 'output.txt';
  final f = File(fname);

  final data = 'an old falcon\n';
  f.writeAsStringSync(data);

  print('Data written to $fname');
}

In the program, we write a string into a file synchronously. The file is created if it does not exist. If it exists, it is overwritten.

import 'dart:io';

We import the dart:io library, which provides file system access.

final f = File(fname);

We create a File instance that points to the target path. No I/O is performed at this point.

final data = 'an old falcon\n';
f.writeAsStringSync(data);

We write the string into the file. The default mode is FileMode.write, which creates the file if it does not exist or truncates it if it does.

$ dart main.dart
Data written to output.txt
$ cat output.txt
an old falcon

Dart writeAsString

The writeAsString method opens the file, writes the string in the given encoding, and closes the file. It returns a Future<File> that completes with the file object once the entire operation has finished. This is the preferred approach in asynchronous code because it does not block the event loop.

main.dart
import 'dart:io';

void main() async {
  final fname = 'output2.txt';
  final f = File(fname);

  final data = 'a stormy night\n';
  await f.writeAsString(data);

  print('Data written to $fname');
}

We write a string to a file with the writeAsString method.

void main() async {

Since we use the asynchronous writeAsString method, we add the async keyword to the main declaration.

await f.writeAsString(data);

The await keyword suspends execution until the Future returned by writeAsString completes. The calling isolate remains free to handle other events while the write is in progress.

Dart writeAsBytesSync

The writeAsBytesSync method synchronously writes a list of bytes to a file. This is useful when you have binary data or when you need to control the encoding explicitly.

main.dart
import 'dart:io';
import 'dart:convert';

void main() {
  final fname = 'bytes.txt';

  final text = "one 🐘 and three 🐋";
  final data = utf8.encode(text);
  final f = File(fname);

  f.writeAsBytesSync(data);
}

In the example, we write a text message containing emojis to a file using writeAsBytesSync. Because emojis require more than one byte in UTF-8, we encode the string explicitly before writing.

import 'dart:convert';

The dart:convert library provides the utf8 codec.

final data = utf8.encode(text);

utf8.encode converts the string into a Uint8List (a list of bytes). Each emoji encodes to four bytes in UTF-8.

f.writeAsBytesSync(data);

The byte list is written to the file synchronously.

$ dart main.dart
$ cat bytes.txt
one 🐘 and three 🐋

Dart fetch image

In the next example, we download a binary file from the network and save it to disk using writeAsBytes.

main.dart
import 'dart:io';
import 'package:http/http.dart' as http;

void main() async {
  final res = await http.get(Uri.http('webcode.me', '/favicon.ico'));
  final bdata = res.bodyBytes;

  final fname = 'favicon.ico';
  final f = File(fname);
  await f.writeAsBytes(bdata);

  print('Saved $fname (${bdata.length} bytes)');
}

The example downloads a small favicon image and saves the raw bytes to a local file.

import 'package:http/http.dart' as http;

We import the http package to perform the HTTP GET request.

final res = await http.get(Uri.http('webcode.me', '/favicon.ico'));
final bdata = res.bodyBytes;

After awaiting the HTTP response, bodyBytes provides the raw response body as a Uint8List.

final f = File(fname);
await f.writeAsBytes(bdata);

We create a File object and write the byte data asynchronously. The file is created if it does not exist.

Dart append to file

To append data to an existing file without overwriting its contents, pass mode: FileMode.append to the write method. If the file does not exist, it is created automatically.

main.dart
import 'dart:io';

void main() async {
  final fname = 'words.txt';

  final words = ['cloud', 'blue', 'book', 'solid'];
  final f = File(fname);

  for (final word in words) {
    await f.writeAsString('$word\n', mode: FileMode.append);
  }

  print(await f.readAsString());
}

Each iteration appends one word followed by a newline to the file.

await f.writeAsString('$word\n', mode: FileMode.append);

Passing mode: FileMode.append opens the file in append mode for each write. Without this parameter, each call would use the default FileMode.write, which truncates the file before writing and would leave only the last word.

$ dart main.dart
cloud
blue
book
solid

Dart IOSink write

The IOSink provides a streaming interface for writing data incrementally. The write method converts the argument to a string and appends it to the stream. Multiple write calls accumulate in a buffer and are flushed when the sink is closed.

main.dart
import 'dart:io';

void main() async {
  final fname = 'test.txt';

  final f = File(fname);
  final sink = f.openWrite();

  sink.write('datetime: ${DateTime.now()}\n');
  sink.write('hostname: ${Platform.localHostname}\n');

  await sink.close();
}

The example writes two lines — the current date/time and the local hostname — to the file via an IOSink.

final sink = f.openWrite();

openWrite returns an IOSink backed by the file. By default it uses FileMode.write, which truncates the file.

sink.write('datetime: ${DateTime.now()}\n');
sink.write('hostname: ${Platform.localHostname}\n');

Each write call adds data to the sink's buffer. String interpolation with ${...} is used to embed runtime values.

await sink.close();

Awaiting sink.close() ensures all buffered data is flushed to disk before the program exits.

Dart IOSink writeln

The writeln method writes an object followed by a newline character. It is a convenient shorthand for write('$object\n').

main.dart
import 'dart:io';

void main() async {
  final fname = 'log.txt';

  final f = File(fname);
  final sink = f.openWrite();

  sink.writeln('INFO  app started');
  sink.writeln('DEBUG loading config');
  sink.writeln('INFO  ready');

  await sink.close();

  print('Log written to $fname');
}

Each writeln call appends the string and a newline to the sink, producing a simple log file.

$ dart main.dart
Log written to log.txt
$ cat log.txt
INFO  app started
DEBUG loading config
INFO  ready

Dart IOSink writeAll

The writeAll method iterates over a collection and writes each element to the sink. An optional separator string is inserted between consecutive elements.

main.dart
import 'dart:io';

void main() async {
  final fname = 'words2.txt';

  final words = ['sky', 'ocean', 'pen', 'rock', 'storm', 'falcon'];

  final f = File(fname);
  final sink = f.openWrite();
  sink.writeAll(words, '\n');
  sink.writeln();

  await sink.close();
}

In the example, we write the contents of a list to a file with each word on its own line.

sink.writeAll(words, '\n');
sink.writeln();

The second argument '\n' is the separator placed between elements. Because no separator is added after the last element, a trailing writeln() call appends the final newline.

$ dart main.dart
$ cat words2.txt
sky
ocean
pen
rock
storm
falcon

Dart write file error handling

File I/O can fail for many reasons: the path may not exist, the process may lack permission, or the disk may be full. Use a try/catch block to handle FileSystemException gracefully.

main.dart
import 'dart:io';

void main() {
  final fname = '/root/protected.txt';
  final f = File(fname);

  try {
    f.writeAsStringSync('Hello, World!\n');
    print('File written successfully');
  } on FileSystemException catch (e) {
    print('Failed to write file: ${e.message}');
    print('Path: ${e.path}');
  }
}

The FileSystemException carries both an error message and the affected path, making it easy to produce a meaningful diagnostic.

} on FileSystemException catch (e) {
  print('Failed to write file: ${e.message}');
  print('Path: ${e.path}');
}

We catch the specific FileSystemException rather than the generic Exception class, which lets us access the message and path properties.

$ dart main.dart
Failed to write file: Permission denied
Path: /root/protected.txt

Source

Dart I/O documentation

In this article we have shown how to write to files in Dart.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.