A tour of the core libraries

This page shows you how to use the major features in Dart’s core libraries.It’s just an overview, and by no means comprehensive.Whenever you need more details about a class,consult the Dart API reference.

  • dart:core
  • Built-in types, collections, and other core functionality.This library is automatically imported into every Dart program.
  • dart:async
  • Support for asynchronous programming, with classes such as Future and Stream.
  • dart:math
  • Mathematical constants and functions, plus a random number generator.
  • dart:convert
  • Encoders and decoders for converting between different data representations, including JSON and UTF-8.
  • dart:html
  • DOM and other APIs for browser-based apps.
  • dart:io
  • I/O for programs that can use the Dart VM,including Flutter apps, servers, and command-line scripts.

This page is just an overview;it covers only a few dart:* librariesand no third-party libraries.

Other places to find library information are thepub.dev site and theDart web developer library guide.You can find API documentation for all dart:* libraries in theDart API reference or, if you’re using Flutter,the Flutter API reference.

DartPad tip: You can play with the code in this page by copying it into a DartPad.

dart:core - numbers, collections, strings, and more

The dart:core library (API reference)provides a small but critical set of built-in functionality.This library is automatically imported into every Dart program.

Printing to the console

The top-level print() method takes a single argument (any Object)and displays that object’s string value (as returned by toString())in the console.

  1. print(anObject);
  2. print('I drink $tea.');

For more information on basic strings and toString(), seeStrings in the language tour.

Numbers

The dart:core library defines the num, int, and double classes, whichhave some basic utilities for working with numbers.

You can convert a string into an integer or double with the parse()methods of int and double, respectively:

  1. assert(int.parse('42') == 42);
  2. assert(int.parse('0x42') == 66);
  3. assert(double.parse('0.50') == 0.5);

Or use the parse() method of num, which creates an integer if possibleand otherwise a double:

  1. assert(num.parse('42') is int);
  2. assert(num.parse('0x42') is int);
  3. assert(num.parse('0.50') is double);

To specify the base of an integer, add a radix parameter:

  1. assert(int.parse('42', radix: 16) == 66);

Use the toString() method to convert anint or double to a string. To specify the number of digits to the rightof the decimal, use toStringAsFixed(). To specify thenumber of significant digits in the string, usetoStringAsPrecision():

  1. // Convert an int to a string.
  2. assert(42.toString() == '42');
  3. // Convert a double to a string.
  4. assert(123.456.toString() == '123.456');
  5. // Specify the number of digits after the decimal.
  6. assert(123.456.toStringAsFixed(2) == '123.46');
  7. // Specify the number of significant figures.
  8. assert(123.456.toStringAsPrecision(2) == '1.2e+2');
  9. assert(double.parse('1.2e+2') == 120.0);

For more information, see the API documentation forint,double, and num. Also seethe dart:math section.

Strings and regular expressions

A string in Dart is an immutable sequence of UTF-16 code units.The language tour has more information aboutstrings.You can use regular expressions (RegExp objects)to search within strings and toreplace parts of strings.

The String class defines such methods as split(), contains(),startsWith(), endsWith(), and more.

Searching inside a string

You can find particular locations within a string, as well as checkwhether a string begins with or ends with a particular pattern. Forexample:

  1. // Check whether a string contains another string.
  2. assert('Never odd or even'.contains('odd'));
  3. // Does a string start with another string?
  4. assert('Never odd or even'.startsWith('Never'));
  5. // Does a string end with another string?
  6. assert('Never odd or even'.endsWith('even'));
  7. // Find the location of a string inside a string.
  8. assert('Never odd or even'.indexOf('odd') == 6);

Extracting data from a string

You can get the individual characters from a string as Strings or ints,respectively. To be precise, you actually get individual UTF-16 codeunits; high-numbered characters such as the treble clef symbol(‘\u{1D11E}’) are two code units apiece.

You can also extract a substring or split a string into a list ofsubstrings:

  1. // Grab a substring.
  2. assert('Never odd or even'.substring(6, 9) == 'odd');
  3. // Split a string using a string pattern.
  4. var parts = 'structured web apps'.split(' ');
  5. assert(parts.length == 3);
  6. assert(parts[0] == 'structured');
  7. // Get a UTF-16 code unit (as a string) by index.
  8. assert('Never odd or even'[0] == 'N');
  9. // Use split() with an empty string parameter to get
  10. // a list of all characters (as Strings); good for
  11. // iterating.
  12. for (var char in 'hello'.split('')) {
  13. print(char);
  14. }
  15. // Get all the UTF-16 code units in the string.
  16. var codeUnitList =
  17. 'Never odd or even'.codeUnits.toList();
  18. assert(codeUnitList[0] == 78);

Converting to uppercase or lowercase

You can easily convert strings to their uppercase and lowercasevariants:

  1. // Convert to uppercase.
  2. assert('structured web apps'.toUpperCase() ==
  3. 'STRUCTURED WEB APPS');
  4. // Convert to lowercase.
  5. assert('STRUCTURED WEB APPS'.toLowerCase() ==
  6. 'structured web apps');

Note: These methods don’t work for every language. For example, the Turkish alphabet’s dotless I is converted incorrectly.

Trimming and empty strings

Remove all leading and trailing white space with trim(). To checkwhether a string is empty (length is zero), use isEmpty.

  1. // Trim a string.
  2. assert(' hello '.trim() == 'hello');
  3. // Check whether a string is empty.
  4. assert(''.isEmpty);
  5. // Strings with only white space are not empty.
  6. assert(' '.isNotEmpty);

Replacing part of a string

Strings are immutable objects, which means you can create them but youcan’t change them. If you look closely at the String API reference,you’ll notice thatnone of the methods actually changes the state of a String. For example,the method replaceAll() returns a new String without changing theoriginal String:

  1. var greetingTemplate = 'Hello, NAME!';
  2. var greeting =
  3. greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');
  4. // greetingTemplate didn't change.
  5. assert(greeting != greetingTemplate);

Building a string

To programmatically generate a string, you can use StringBuffer. AStringBuffer doesn’t generate a new String object until toString() iscalled. The writeAll() method has an optional second parameter thatlets you specify a separator—in this case, a space.

  1. var sb = StringBuffer();
  2. sb
  3. ..write('Use a StringBuffer for ')
  4. ..writeAll(['efficient', 'string', 'creation'], ' ')
  5. ..write('.');
  6. var fullString = sb.toString();
  7. assert(fullString ==
  8. 'Use a StringBuffer for efficient string creation.');

Regular expressions

The RegExp class provides the same capabilities as JavaScript regularexpressions. Use regular expressions for efficient searching and patternmatching of strings.

  1. // Here's a regular expression for one or more digits.
  2. var numbers = RegExp(r'\d+');
  3. var allCharacters = 'llamas live fifteen to twenty years';
  4. var someDigits = 'llamas live 15 to 20 years';
  5. // contains() can use a regular expression.
  6. assert(!allCharacters.contains(numbers));
  7. assert(someDigits.contains(numbers));
  8. // Replace every match with another string.
  9. var exedOut = someDigits.replaceAll(numbers, 'XX');
  10. assert(exedOut == 'llamas live XX to XX years');

You can work directly with the RegExp class, too. The Match classprovides access to a regular expression match.

  1. var numbers = RegExp(r'\d+');
  2. var someDigits = 'llamas live 15 to 20 years';
  3. // Check whether the reg exp has a match in a string.
  4. assert(numbers.hasMatch(someDigits));
  5. // Loop through all matches.
  6. for (var match in numbers.allMatches(someDigits)) {
  7. print(match.group(0)); // 15, then 20
  8. }

More information

Refer to the String API reference for a full list ofmethods. Also see the API reference for StringBuffer,Pattern,RegExp, and Match.

Collections

Dart ships with a core collections API, which includes classes forlists, sets, and maps.

Lists

As the language tour shows, you can use literals to create andinitialize lists. Alternatively, use one of the Listconstructors. The List class also defines several methods for addingitems to and removing items from lists.

  1. // Use a List constructor.
  2. var vegetables = List();
  3. // Or simply use a list literal.
  4. var fruits = ['apples', 'oranges'];
  5. // Add to a list.
  6. fruits.add('kiwis');
  7. // Add multiple items to a list.
  8. fruits.addAll(['grapes', 'bananas']);
  9. // Get the list length.
  10. assert(fruits.length == 5);
  11. // Remove a single item.
  12. var appleIndex = fruits.indexOf('apples');
  13. fruits.removeAt(appleIndex);
  14. assert(fruits.length == 4);
  15. // Remove all elements from a list.
  16. fruits.clear();
  17. assert(fruits.isEmpty);

Use indexOf() to find the index of an object in a list:

  1. var fruits = ['apples', 'oranges'];
  2. // Access a list item by index.
  3. assert(fruits[0] == 'apples');
  4. // Find an item in a list.
  5. assert(fruits.indexOf('apples') == 0);

Sort a list using the sort() method. You can provide a sortingfunction that compares two objects. This sorting function must return <0 for smaller, 0 for the same, and > 0 for bigger. The followingexample uses compareTo(), which is defined byComparable and implemented by String.

  1. var fruits = ['bananas', 'apples', 'oranges'];
  2. // Sort a list.
  3. fruits.sort((a, b) => a.compareTo(b));
  4. assert(fruits[0] == 'apples');

Lists are parameterized types, so you can specify the type that a listshould contain:

  1. // This list should contain only strings.
  2. var fruits = List<String>();
  3. fruits.add('apples');
  4. var fruit = fruits[0];
  5. assert(fruit is String);
  1. fruits.add(5); // Error: 'int' can't be assigned to 'String'

Refer to the List API reference for a full list of methods.

Sets

A set in Dart is an unordered collection of unique items. Because a setis unordered, you can’t get a set’s items by index (position).

  1. var ingredients = Set();
  2. ingredients.addAll(['gold', 'titanium', 'xenon']);
  3. assert(ingredients.length == 3);
  4. // Adding a duplicate item has no effect.
  5. ingredients.add('gold');
  6. assert(ingredients.length == 3);
  7. // Remove an item from a set.
  8. ingredients.remove('gold');
  9. assert(ingredients.length == 2);

Use contains() and containsAll() to check whether one or moreobjects are in a set:

  1. var ingredients = Set();
  2. ingredients.addAll(['gold', 'titanium', 'xenon']);
  3. // Check whether an item is in the set.
  4. assert(ingredients.contains('titanium'));
  5. // Check whether all the items are in the set.
  6. assert(ingredients.containsAll(['titanium', 'xenon']));

An intersection is a set whose items are in two other sets.

  1. var ingredients = Set();
  2. ingredients.addAll(['gold', 'titanium', 'xenon']);
  3. // Create the intersection of two sets.
  4. var nobleGases = Set.from(['xenon', 'argon']);
  5. var intersection = ingredients.intersection(nobleGases);
  6. assert(intersection.length == 1);
  7. assert(intersection.contains('xenon'));

Refer to the Set API reference for a full list of methods.

Maps

A map, commonly known as a dictionary or hash, is an unorderedcollection of key-value pairs. Maps associate a key to some value foreasy retrieval. Unlike in JavaScript, Dart objects are not maps.

You can declare a map using a terse literal syntax, or you can use atraditional constructor:

  1. // Maps often use strings as keys.
  2. var hawaiianBeaches = {
  3. 'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  4. 'Big Island': ['Wailea Bay', 'Pololu Beach'],
  5. 'Kauai': ['Hanalei', 'Poipu']
  6. };
  7. // Maps can be built from a constructor.
  8. var searchTerms = Map();
  9. // Maps are parameterized types; you can specify what
  10. // types the key and value should be.
  11. var nobleGases = Map<int, String>();

You add, get, and set map items using the bracket syntax. Use remove()to remove a key and its value from a map.

  1. var nobleGases = {54: 'xenon'};
  2. // Retrieve a value with a key.
  3. assert(nobleGases[54] == 'xenon');
  4. // Check whether a map contains a key.
  5. assert(nobleGases.containsKey(54));
  6. // Remove a key and its value.
  7. nobleGases.remove(54);
  8. assert(!nobleGases.containsKey(54));

You can retrieve all the values or all the keys from a map:

  1. var hawaiianBeaches = {
  2. 'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  3. 'Big Island': ['Wailea Bay', 'Pololu Beach'],
  4. 'Kauai': ['Hanalei', 'Poipu']
  5. };
  6. // Get all the keys as an unordered collection
  7. // (an Iterable).
  8. var keys = hawaiianBeaches.keys;
  9. assert(keys.length == 3);
  10. assert(Set.from(keys).contains('Oahu'));
  11. // Get all the values as an unordered collection
  12. // (an Iterable of Lists).
  13. var values = hawaiianBeaches.values;
  14. assert(values.length == 3);
  15. assert(values.any((v) => v.contains('Waikiki')));

To check whether a map contains a key, use containsKey(). Because mapvalues can be null, you cannot rely on simply getting the value for thekey and checking for null to determine the existence of a key.

  1. var hawaiianBeaches = {
  2. 'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  3. 'Big Island': ['Wailea Bay', 'Pololu Beach'],
  4. 'Kauai': ['Hanalei', 'Poipu']
  5. };
  6. assert(hawaiianBeaches.containsKey('Oahu'));
  7. assert(!hawaiianBeaches.containsKey('Florida'));

Use the putIfAbsent() method when you want to assign a value to a keyif and only if the key does not already exist in a map. You must providea function that returns the value.

  1. var teamAssignments = {};
  2. teamAssignments.putIfAbsent(
  3. 'Catcher', () => pickToughestKid());
  4. assert(teamAssignments['Catcher'] != null);

Refer to the Map API reference for a full list of methods.

Common collection methods

List, Set, and Map share common functionality found in many collections.Some of this common functionality is defined by the Iterable class,which List and Set implement.

Note: Although Map doesn’t implement Iterable, you can get Iterables from it using the Map keys and values properties.

Use isEmpty or isNotEmpty to check whether a list, set, or map has items:

  1. var coffees = [];
  2. var teas = ['green', 'black', 'chamomile', 'earl grey'];
  3. assert(coffees.isEmpty);
  4. assert(teas.isNotEmpty);

To apply a function to each item in a list, set, or map, you can useforEach():

  1. var teas = ['green', 'black', 'chamomile', 'earl grey'];
  2. teas.forEach((tea) => print('I drink $tea'));

When you invoke forEach() on a map, your function must take twoarguments (the key and value):

  1. hawaiianBeaches.forEach((k, v) {
  2. print('I want to visit $k and swim at $v');
  3. // I want to visit Oahu and swim at
  4. // [Waikiki, Kailua, Waimanalo], etc.
  5. });

Iterables provide the map() method, which gives you all the results ina single object:

  1. var teas = ['green', 'black', 'chamomile', 'earl grey'];
  2. var loudTeas = teas.map((tea) => tea.toUpperCase());
  3. loudTeas.forEach(print);

Note: The object returned by map() is an Iterable that’s lazily evaluated: your function isn’t called until you ask for an item from the returned object.

To force your function to be called immediately on each item, usemap().toList() or map().toSet():

  1. var loudTeas =
  2. teas.map((tea) => tea.toUpperCase()).toList();

Use Iterable’s where() method to get all the items that match acondition. Use Iterable’s any() and every() methods to check whethersome or all items match a condition.

  1. var teas = ['green', 'black', 'chamomile', 'earl grey'];
  2. // Chamomile is not caffeinated.
  3. bool isDecaffeinated(String teaName) =>
  4. teaName == 'chamomile';
  5. // Use where() to find only the items that return true
  6. // from the provided function.
  7. var decaffeinatedTeas =
  8. teas.where((tea) => isDecaffeinated(tea));
  9. // or teas.where(isDecaffeinated)
  10. // Use any() to check whether at least one item in the
  11. // collection satisfies a condition.
  12. assert(teas.any(isDecaffeinated));
  13. // Use every() to check whether all the items in a
  14. // collection satisfy a condition.
  15. assert(!teas.every(isDecaffeinated));

For a full list of methods, refer to the Iterable API reference,as well as those for List,Set, and Map.

URIs

The Uri class providesfunctions to encode and decode strings for use in URIs (which you mightknow as URLs). These functions handle characters that are special forURIs, such as & and =. The Uri class also parses and exposes thecomponents of a URI—host, port, scheme, and so on.

Encoding and decoding fully qualified URIs

To encode and decode characters except those with special meaning in aURI (such as /, :, &, #), use the encodeFull() anddecodeFull() methods. These methods are good for encoding or decodinga fully qualified URI, leaving intact special URI characters.

  1. var uri = 'https://example.org/api?foo=some message';
  2. var encoded = Uri.encodeFull(uri);
  3. assert(encoded ==
  4. 'https://example.org/api?foo=some%20message');
  5. var decoded = Uri.decodeFull(encoded);
  6. assert(uri == decoded);

Notice how only the space between some and message was encoded.

Encoding and decoding URI components

To encode and decode all of a string’s characters that have specialmeaning in a URI, including (but not limited to) /, &, and :, usethe encodeComponent() and decodeComponent() methods.

  1. var uri = 'https://example.org/api?foo=some message';
  2. var encoded = Uri.encodeComponent(uri);
  3. assert(encoded ==
  4. 'https%3A%2F%2Fexample.org%2Fapi%3Ffoo%3Dsome%20message');
  5. var decoded = Uri.decodeComponent(encoded);
  6. assert(uri == decoded);

Notice how every special character is encoded. For example, / isencoded to %2F.

Parsing URIs

If you have a Uri object or a URI string, you can get its parts usingUri fields such as path. To create a Uri from a string, use theparse() static method:

  1. var uri =
  2. Uri.parse('https://example.org:8080/foo/bar#frag');
  3. assert(uri.scheme == 'https');
  4. assert(uri.host == 'example.org');
  5. assert(uri.path == '/foo/bar');
  6. assert(uri.fragment == 'frag');
  7. assert(uri.origin == 'https://example.org:8080');

See the Uri API reference for more URI components that you can get.

Building URIs

You can build up a URI from individual parts using the Uri()constructor:

  1. var uri = Uri(
  2. scheme: 'https',
  3. host: 'example.org',
  4. path: '/foo/bar',
  5. fragment: 'frag');
  6. assert(
  7. uri.toString() == 'https://example.org/foo/bar#frag');

Dates and times

A DateTime object is a point in time. The time zone is either UTC or thelocal time zone.

You can create DateTime objects using several constructors:

  1. // Get the current date and time.
  2. var now = DateTime.now();
  3. // Create a new DateTime with the local time zone.
  4. var y2k = DateTime(2000); // January 1, 2000
  5. // Specify the month and day.
  6. y2k = DateTime(2000, 1, 2); // January 2, 2000
  7. // Specify the date as a UTC time.
  8. y2k = DateTime.utc(2000); // 1/1/2000, UTC
  9. // Specify a date and time in ms since the Unix epoch.
  10. y2k = DateTime.fromMillisecondsSinceEpoch(946684800000,
  11. isUtc: true);
  12. // Parse an ISO 8601 date.
  13. y2k = DateTime.parse('2000-01-01T00:00:00Z');

The millisecondsSinceEpoch property of a date returns the number ofmilliseconds since the “Unix epoch”—January 1, 1970, UTC:

  1. // 1/1/2000, UTC
  2. var y2k = DateTime.utc(2000);
  3. assert(y2k.millisecondsSinceEpoch == 946684800000);
  4. // 1/1/1970, UTC
  5. var unixEpoch = DateTime.utc(1970);
  6. assert(unixEpoch.millisecondsSinceEpoch == 0);

Use the Duration class to calculate the difference between two dates andto shift a date forward or backward:

  1. var y2k = DateTime.utc(2000);
  2. // Add one year.
  3. var y2001 = y2k.add(Duration(days: 366));
  4. assert(y2001.year == 2001);
  5. // Subtract 30 days.
  6. var december2000 = y2001.subtract(Duration(days: 30));
  7. assert(december2000.year == 2000);
  8. assert(december2000.month == 12);
  9. // Calculate the difference between two dates.
  10. // Returns a Duration object.
  11. var duration = y2001.difference(y2k);
  12. assert(duration.inDays == 366); // y2k was a leap year.

Warning: Using a Duration to shift a DateTime by days can be problematic, due to clock shifts (to daylight saving time, for example). Use UTC dates if you must shift days.

For a full list of methods,refer to the API reference for DateTime and Duration.

Utility classes

The core library contains various utility classes, useful for sorting,mapping values, and iterating.

Comparing objects

Implement the Comparableinterface to indicate that an object can be compared to another object,usually for sorting. The compareTo() method returns < 0 forsmaller, 0 for the same, and > 0 for bigger.

  1. class Line implements Comparable<Line> {
  2. final int length;
  3. const Line(this.length);
  4. @override
  5. int compareTo(Line other) => length - other.length;
  6. }
  7. void main() {
  8. var short = const Line(1);
  9. var long = const Line(100);
  10. assert(short.compareTo(long) < 0);
  11. }

Implementing map keys

Each object in Dart automatically provides an integer hash code, andthus can be used as a key in a map. However, you can override thehashCode getter to generate a custom hash code. If you do, you mightalso want to override the == operator. Objects that are equal (via==) must have identical hash codes. A hash code doesn’t have to beunique, but it should be well distributed.

  1. class Person {
  2. final String firstName, lastName;
  3. Person(this.firstName, this.lastName);
  4. // Override hashCode using strategy from Effective Java,
  5. // Chapter 11.
  6. @override
  7. int get hashCode {
  8. int result = 17;
  9. result = 37 * result + firstName.hashCode;
  10. result = 37 * result + lastName.hashCode;
  11. return result;
  12. }
  13. // You should generally implement operator == if you
  14. // override hashCode.
  15. @override
  16. bool operator ==(dynamic other) {
  17. if (other is! Person) return false;
  18. Person person = other;
  19. return (person.firstName == firstName &&
  20. person.lastName == lastName);
  21. }
  22. }
  23. void main() {
  24. var p1 = Person('Bob', 'Smith');
  25. var p2 = Person('Bob', 'Smith');
  26. var p3 = 'not a person';
  27. assert(p1.hashCode == p2.hashCode);
  28. assert(p1 == p2);
  29. assert(p1 != p3);
  30. }

Iteration

The Iterable and Iterator classessupport for-in loops. Extend (if possible) or implement Iterablewhenever you create a class that can provide Iterators for use in for-inloops. Implement Iterator to define the actual iteration ability.

  1. class Process {
  2. // Represents a process...
  3. }
  4. class ProcessIterator implements Iterator<Process> {
  5. @override
  6. Process get current => ...
  7. @override
  8. bool moveNext() => ...
  9. }
  10. // A mythical class that lets you iterate through all
  11. // processes. Extends a subclass of [Iterable].
  12. class Processes extends IterableBase<Process> {
  13. @override
  14. final Iterator<Process> iterator = ProcessIterator();
  15. }
  16. void main() {
  17. // Iterable objects can be used with for-in.
  18. for (var process in Processes()) {
  19. // Do something with the process.
  20. }
  21. }

Exceptions

The Dart core library defines many common exceptions and errors.Exceptions are considered conditions that you can plan ahead for andcatch. Errors are conditions that you don’t expect or plan for.

A couple of the most common errors are:

  • NoSuchMethodError
  • Thrown when a receiving object (which might be null) does notimplement a method.

  • ArgumentError

  • Can be thrown by a method that encounters an unexpected argument.

Throwing an application-specific exception is a common way to indicatethat an error has occurred. You can define a custom exception byimplementing the Exception interface:

  1. class FooException implements Exception {
  2. final String msg;
  3. const FooException([this.msg]);
  4. @override
  5. String toString() => msg ?? 'FooException';
  6. }

For more information, seeExceptions(in the language tour) and the Exception API reference.

dart:async - asynchronous programming

Asynchronous programming often uses callback functions, but Dartprovides alternatives: Future and Stream objects. AFuture is like a promise for a result to be provided sometime in thefuture. A Stream is a way to get a sequence of values, such as events.Future, Stream, and more are in thedart:async library (API reference).

Note: You don’t always need to use the Future or Stream APIs directly. The Dart language supports asynchronous coding using keywords such as async and await. See the asynchronous programming codelab for details.

The dart:async library works in both web apps and command-line apps. Touse it, import dart:async:

  1. import 'dart:async';

Version note: As of Dart 2.1, you don’t need to import dart:async to use the Future and Stream APIs, because dart:core exports those classes.

Future

Future objects appear throughout the Dart libraries, often as the objectreturned by an asynchronous method. When a future completes, its valueis ready to use.

Using await

Before you directly use the Future API, consider using await instead.Code that uses await expressions can be easier to understandthan code that uses the Future API.

Consider the following function. It uses Future’s then() methodto execute three asynchronous functions in a row,waiting for each one to complete before executing the next one.

  1. runUsingFuture() {
  2. // ...
  3. findEntryPoint().then((entryPoint) {
  4. return runExecutable(entryPoint, args);
  5. }).then(flushThenExit);
  6. }

The equivalent code with await expressionslooks more like synchronous code:

  1. runUsingAsyncAwait() async {
  2. // ...
  3. var entryPoint = await findEntryPoint();
  4. var exitCode = await runExecutable(entryPoint, args);
  5. await flushThenExit(exitCode);
  6. }

An async function can catch exceptions from Futures.For example:

  1. var entryPoint = await findEntryPoint();
  2. try {
  3. var exitCode = await runExecutable(entryPoint, args);
  4. await flushThenExit(exitCode);
  5. } catch (e) {
  6. // Handle the error...
  7. }

Important: Async functions return Futures. If you don’t want your function to return a future, then use a different solution. For example, you might call an async function from your function.

For more information on using await and related Dart language features,see the asynchronous programming codelab.

Basic usage

You can use then() to schedule code that runs when the future completes. Forexample, HttpRequest.getString() returns a Future, since HTTP requestscan take a while. Using then() lets you run some code when that Futurehas completed and the promised string value is available:

  1. HttpRequest.getString(url).then((String result) {
  2. print(result);
  3. });

Use catchError() to handle any errors or exceptions that a Futureobject might throw.

  1. HttpRequest.getString(url).then((String result) {
  2. print(result);
  3. }).catchError((e) {
  4. // Handle or ignore the error.
  5. });

The then().catchError() pattern is the asynchronous version oftry-catch.

Important: Be sure to invoke catchError() on the result of then()—not on the result of the original Future. Otherwise, the catchError() can handle errors only from the original Future’s computation, but not from the handler registered by then().

Chaining multiple asynchronous methods

The then() method returns a Future, providing a useful way to runmultiple asynchronous functions in a certain order. If the callbackregistered with then() returns a Future, then() returns anequivalent Future. If the callback returns a value of any other type,then() creates a new Future that completes with the value.

  1. Future result = costlyQuery(url);
  2. result
  3. .then((value) => expensiveWork(value))
  4. .then((_) => lengthyComputation())
  5. .then((_) => print('Done!'))
  6. .catchError((exception) {
  7. /* Handle exception... */
  8. });

In the preceding example, the methods run in the following order:

  • costlyQuery()
  • expensiveWork()
  • lengthyComputation()Here is the same code written using await:
  1. try {
  2. final value = await costlyQuery(url);
  3. await expensiveWork(value);
  4. await lengthyComputation();
  5. print('Done!');
  6. } catch (e) {
  7. /* Handle exception... */
  8. }

Waiting for multiple futures

Sometimes your algorithm needs to invoke many asynchronous functions andwait for them all to complete before continuing. Use the Future.wait()static method to manage multiple Futures and wait for them to complete:

  1. Future deleteLotsOfFiles() async => ...
  2. Future copyLotsOfFiles() async => ...
  3. Future checksumLotsOfOtherFiles() async => ...
  4. await Future.wait([
  5. deleteLotsOfFiles(),
  6. copyLotsOfFiles(),
  7. checksumLotsOfOtherFiles(),
  8. ]);
  9. print('Done with all the long steps!');

Stream

Stream objects appear throughout Dart APIs, representing sequences ofdata. For example, HTML events such as button clicks are delivered usingstreams. You can also read a file as a stream.

Using an asynchronous for loop

Sometimes you can use an asynchronous for loop (await for)instead of using the Stream API.

Consider the following function.It uses Stream’s listen() methodto subscribe to a list of files,passing in a function literal that searches each file or directory.

  1. void main(List<String> arguments) {
  2. // ...
  3. FileSystemEntity.isDirectory(searchPath).then((isDir) {
  4. if (isDir) {
  5. final startingDir = Directory(searchPath);
  6. startingDir
  7. .list(
  8. recursive: argResults[recursive],
  9. followLinks: argResults[followLinks])
  10. .listen((entity) {
  11. if (entity is File) {
  12. searchFile(entity, searchTerms);
  13. }
  14. });
  15. } else {
  16. searchFile(File(searchPath), searchTerms);
  17. }
  18. });
  19. }

The equivalent code with await expressions,including an asynchronous for loop (await for),looks more like synchronous code:

  1. Future main(List<String> arguments) async {
  2. // ...
  3. if (await FileSystemEntity.isDirectory(searchPath)) {
  4. final startingDir = Directory(searchPath);
  5. await for (var entity in startingDir.list(
  6. recursive: argResults[recursive],
  7. followLinks: argResults[followLinks])) {
  8. if (entity is File) {
  9. searchFile(entity, searchTerms);
  10. }
  11. }
  12. } else {
  13. searchFile(File(searchPath), searchTerms);
  14. }
  15. }

Important: Before using await for, make sure that it makes the code clearer and that you really do want to wait for all of the stream’s results. For example, you usually should not use await for for DOM event listeners, because the DOM sends endless streams of events. If you use await for to register two DOM event listeners in a row, then the second kind of event is never handled.

For more information on using await and relatedDart language features, see theasynchronous programming codelab.

Listening for stream data

To get each value as it arrives, either use await for orsubscribe to the stream using the listen() method:

  1. // Find a button by ID and add an event handler.
  2. querySelector('#submitInfo').onClick.listen((e) {
  3. // When the button is clicked, it runs this code.
  4. submitData();
  5. });

In this example, the onClick property is a Stream object provided bythe “submitInfo” button.

If you care about only one event, you can get it using a property suchas first, last, or single. To test the event before handling it,use a method such as firstWhere(), lastWhere(), or singleWhere().

If you care about a subset of events, you can use methods such asskip(), skipWhile(), take(), takeWhile(), and where().

Transforming stream data

Often, you need to change the format of a stream’s data before you canuse it. Use the transform() method to produce a stream with adifferent type of data:

  1. var lines = inputStream
  2. .transform(utf8.decoder)
  3. .transform(LineSplitter());

This example uses two transformers. First it uses utf8.decoder totransform the stream of integers into a stream of strings. Then it usesa LineSplitter to transform the stream of strings into a stream ofseparate lines. These transformers are from the dart:convert library (see thedart:convert section).

Handling errors and completion

How you specify error and completion handling codedepends on whether you use an asynchronous for loop (await for)or the Stream API.

If you use an asynchronous for loop,then use try-catch to handle errors.Code that executes after the stream is closedgoes after the asynchronous for loop.

  1. Future readFileAwaitFor() async {
  2. var config = File('config.txt');
  3. Stream<List<int>> inputStream = config.openRead();
  4.  
  5. var lines = inputStream
  6. .transform(utf8.decoder)
  7. .transform(LineSplitter());
  8. try {
  9. await for (var line in lines) {
  10. print('Got ${line.length} characters from stream');
  11. }
  12. print('file is now closed');
  13. } catch (e) {
  14. print(e);
  15. }
  16. }

If you use the Stream API,then handle errors by registering an onError listener.Run code after the stream is closed by registeringan onDone listener.

  1. var config = File('config.txt');
  2. Stream<List<int>> inputStream = config.openRead();
  3.  
  4. inputStream
  5. .transform(utf8.decoder)
  6. .transform(LineSplitter())
  7. .listen((String line) {
  8. print('Got ${line.length} characters from stream');
  9. }, onDone: () {
  10. print('file is now closed');
  11. }, onError: (e) {
  12. print(e);
  13. });

More information

For some examples of using Future and Stream in command-line apps,see the dart:io tour.Also see these articles, codelabs, and tutorials:

dart:math - math and random

The dart:math library (API reference)provides common functionality such as sine and cosine,maximum and minimum, and constants such as pi and e. Most of thefunctionality in the Math library is implemented as top-level functions.

To use this library in your app, import dart:math.

  1. import 'dart:math';

Trigonometry

The Math library provides basic trigonometric functions:

  1. // Cosine
  2. assert(cos(pi) == -1.0);
  3. // Sine
  4. var degrees = 30;
  5. var radians = degrees * (pi / 180);
  6. // radians is now 0.52359.
  7. var sinOf30degrees = sin(radians);
  8. // sin 30° = 0.5
  9. assert((sinOf30degrees - 0.5).abs() < 0.01);

Note: These functions use radians, not degrees!

Maximum and minimum

The Math library provides max() and min() methods:

  1. assert(max(1, 1000) == 1000);
  2. assert(min(1, -1000) == -1000);

Math constants

Find your favorite constants—pi, e, and more—in the Math library:

  1. // See the Math library for additional constants.
  2. print(e); // 2.718281828459045
  3. print(pi); // 3.141592653589793
  4. print(sqrt2); // 1.4142135623730951

Random numbers

Generate random numbers with the Random class. You canoptionally provide a seed to the Random constructor.

  1. var random = Random();
  2. random.nextDouble(); // Between 0.0 and 1.0: [0, 1)
  3. random.nextInt(10); // Between 0 and 9.

You can even generate random booleans:

  1. var random = Random();
  2. random.nextBool(); // true or false

More information

Refer to the Math API reference for a full list of methods.Also see the API reference for num,int, and double.

dart:convert - decoding and encoding JSON, UTF-8, and more

The dart:convert library (API reference)has converters for JSON and UTF-8, as well as support for creatingadditional converters. JSON is a simple text format for representingstructured objects and collections. UTF-8 is a common variable-widthencoding that can represent every character in the Unicode characterset.

The dart:convert library works in both web apps and command-line apps.To use it, import dart:convert.

  1. import 'dart:convert';

Decoding and encoding JSON

Decode a JSON-encoded string into a Dart object with jsonDecode():

  1. // NOTE: Be sure to use double quotes ("),
  2. // not single quotes ('), inside the JSON string.
  3. // This string is JSON, not Dart.
  4. var jsonString = '''
  5. [
  6. {"score": 40},
  7. {"score": 80}
  8. ]
  9. ''';
  10. var scores = jsonDecode(jsonString);
  11. assert(scores is List);
  12. var firstScore = scores[0];
  13. assert(firstScore is Map);
  14. assert(firstScore['score'] == 40);

Encode a supported Dart object into a JSON-formatted string withjsonEncode():

  1. var scores = [
  2. {'score': 40},
  3. {'score': 80},
  4. {'score': 100, 'overtime': true, 'special_guest': null}
  5. ];
  6. var jsonText = jsonEncode(scores);
  7. assert(jsonText ==
  8. '[{"score":40},{"score":80},'
  9. '{"score":100,"overtime":true,'
  10. '"special_guest":null}]');

Only objects of type int, double, String, bool, null, List, or Map (withstring keys) are directly encodable into JSON. List and Map objects areencoded recursively.

You have two options for encoding objects that aren’t directlyencodable. The first is to invoke encode() with a second argument: afunction that returns an object that is directly encodable. Your secondoption is to omit the second argument, in which case the encoder callsthe object’s toJson() method.

For more examples and links to JSON-related packages, seeUsing JSON.

Decoding and encoding UTF-8 characters

Use utf8.decode() to decode UTF8-encoded bytes to a Dart string:

  1. List<int> utf8Bytes = [
  2. 0xc3, 0x8e, 0xc3, 0xb1, 0xc5, 0xa3, 0xc3, 0xa9,
  3. 0x72, 0xc3, 0xb1, 0xc3, 0xa5, 0xc5, 0xa3, 0xc3,
  4. 0xae, 0xc3, 0xb6, 0xc3, 0xb1, 0xc3, 0xa5, 0xc4,
  5. 0xbc, 0xc3, 0xae, 0xc5, 0xbe, 0xc3, 0xa5, 0xc5,
  6. 0xa3, 0xc3, 0xae, 0xe1, 0xbb, 0x9d, 0xc3, 0xb1
  7. ];
  8. var funnyWord = utf8.decode(utf8Bytes);
  9. assert(funnyWord == 'Îñţérñåţîöñåļîžåţîờñ');

To convert a stream of UTF-8 characters into a Dart string, specifyutf8.decoder to the Stream transform() method:

  1. var lines =
  2. utf8.decoder.bind(inputStream).transform(LineSplitter());
  3. try {
  4. await for (var line in lines) {
  5. print('Got ${line.length} characters from stream');
  6. }
  7. print('file is now closed');
  8. } catch (e) {
  9. print(e);
  10. }

Use utf8.encode() to encode a Dart string as a list of UTF8-encodedbytes:

  1. List<int> encoded = utf8.encode('Îñţérñåţîöñåļîžåţîờñ');
  2. assert(encoded.length == utf8Bytes.length);
  3. for (int i = 0; i < encoded.length; i++) {
  4. assert(encoded[i] == utf8Bytes[i]);
  5. }

Other functionality

The dart:convert library also has converters for ASCII and ISO-8859-1(Latin1). For details, see the API reference for the dart:convert library.

dart:html - browser-based apps

Use the dart:html library to program the browser, manipulate objects andelements in the DOM, and access HTML5 APIs. DOM stands for Document ObjectModel, which describes the hierarchy of an HTML page.

Other common uses of dart:html are manipulating styles (CSS), gettingdata using HTTP requests, and exchanging data usingWebSockets.HTML5 (and dart:html) has manyadditional APIs that this section doesn’t cover. Only web apps can usedart:html, not command-line apps.

Note: For a higher level approach to web app UIs, use a web framework such as AngularDart.

To use the HTML library in your web app, import dart:html:

  1. import 'dart:html';

Manipulating the DOM

To use the DOM, you need to know about windows, documents,elements, and nodes.

A Window object representsthe actual window of the web browser. Each Window has a Document object,which points to the document that’s currently loaded. The Window objectalso has accessors to various APIs such as IndexedDB (for storing data),requestAnimationFrame (for animations), and more. In tabbed browsers,each tab has its own Window object.

With the Document object, you can create and manipulate Element objectswithin the document. Note that the document itself is an element and can bemanipulated.

The DOM models a tree ofNodes. These nodes are oftenelements, but they can also be attributes, text, comments, and other DOMtypes. Except for the root node, which has no parent, each node in theDOM has one parent and might have many children.

Finding elements

To manipulate an element, you first need an object that represents it.You can get this object using a query.

Find one or more elements using the top-level functionsquerySelector() and querySelectorAll(). You can query by ID, class, tag, name, orany combination of these. The CSS Selector Specificationguide defines the formats of theselectors such as using a # prefix to specify IDs and a period (.) forclasses.

The querySelector() function returns the first element that matchesthe selector, while querySelectorAll()returns a collection of elementsthat match the selector.

  1. // Find an element by id (an-id).
  2. Element elem1 = querySelector('#an-id');
  3. // Find an element by class (a-class).
  4. Element elem2 = querySelector('.a-class');
  5. // Find all elements by tag (<div>).
  6. List<Element> elems1 = querySelectorAll('div');
  7. // Find all text inputs.
  8. List<Element> elems2 = querySelectorAll(
  9. 'input[type="text"]',
  10. );
  11. // Find all elements with the CSS class 'class'
  12. // inside of a <p> that is inside an element with
  13. // the ID 'id'.
  14. List<Element> elems3 = querySelectorAll('#id p.class');

Manipulating elements

You can use properties to change the state of an element. Node and itssubtype Element define the properties that all elements have. Forexample, all elements have classes, hidden, id, style, andtitle properties that you can use to set state. Subclasses of Elementdefine additional properties, such as the href property ofAnchorElement.

Consider this example of specifying an anchor element in HTML:

  1. <a id="example" href="/another/example">link text</a>

This <a> tag specifies an element with an href attribute and a textnode (accessible via a text property) that contains the string“linktext”. To change the URL that the link goes to, you can useAnchorElement’s href property:

var anchor = querySelector('#example') as AnchorElement;
anchor.href = 'https://dart.dev';

Often you need to set properties on multiple elements. For example, thefollowing code sets the hidden property of all elements that have aclass of “mac”, “win”, or “linux”. Setting the hidden property to truehas the same effect as adding display:none to the CSS.

<!-- In HTML: -->
<p>
  <span class="linux">Words for Linux</span>
  <span class="macos">Words for Mac</span>
  <span class="windows">Words for Windows</span>
</p>
// In Dart:
final osList = ['macos', 'windows', 'linux'];
final userOs = determineUserOs();

// For each possible OS...
for (var os in osList) {
  // Matches user OS?
  bool shouldShow = (os == userOs);

  // Find all elements with class=os. For example, if
  // os == 'windows', call querySelectorAll('.windows')
  // to find all elements with the class "windows".
  // Note that '.$os' uses string interpolation.
  for (var elem in querySelectorAll('.$os')) {
    elem.hidden = !shouldShow; // Show or hide.
  }
}

When the right property isn’t available or convenient, you can useElement’s attributes property. This property is aMap<String, String>, where the keys are attribute names. For a list ofattribute names and their meanings, see the MDN Attributespage. Here’s anexample of setting an attribute’s value:

elem.attributes['someAttribute'] = 'someValue';

Creating elements

You can add to existing HTML pages by creating new elements andattaching them to the DOM. Here’s an example of creating a paragraph(<p>) element:

var elem = ParagraphElement();
elem.text = 'Creating is easy!';

You can also create an element by parsing HTML text. Any child elementsare also parsed and created.

var elem2 = Element.html(
  '<p>Creating <em>is</em> easy!</p>',
);

Note that elem2 is a ParagraphElement in the preceding example.

Attach the newly created element to the document by assigning a parentto the element. You can add an element to any existing element’schildren. In the following example, body is an element, and its childelements are accessible (as a List<Element>) from the childrenproperty.

document.body.children.add(elem2);

Adding, replacing, and removing nodes

Recall that elements are just a kind of node. You can find all thechildren of a node using the nodes property of Node, which returns aList<Node> (as opposed to children, which omits non-Element nodes).Once you have this list, you can use the usual List methods andoperators to manipulate the children of the node.

To add a node as the last child of its parent, use the List add()method:

querySelector('#inputs').nodes.add(elem);

To replace a node, use the Node replaceWith() method:

querySelector('#status').replaceWith(elem);

To remove a node, use the Node remove() method:

// Find a node by ID, and remove it from the DOM.
querySelector('#expendable').remove();

Manipulating CSS styles

CSS, or cascading style sheets, defines the presentation styles of DOMelements. You can change the appearance of an element by attaching IDand class attributes to it.

Each element has a classes field, which is a list. Add and remove CSSclasses simply by adding and removing strings from this collection. Forexample, the following sample adds the warning class to an element:

var elem = querySelector('#message');
elem.classes.add('warning');

It’s often very efficient to find an element by ID. You can dynamicallyset an element ID with the id property:

var message = DivElement();
message.id = 'message2';
message.text = 'Please subscribe to the Dart mailing list.';

You can reduce the redundant text in this example by using methodcascades:

var message = DivElement()
  ..id = 'message2'
  ..text = 'Please subscribe to the Dart mailing list.';

While using IDs and classes to associate an element with a set of stylesis best practice, sometimes you want to attach a specific style directlyto the element:

message.style
  ..fontWeight = 'bold'
  ..fontSize = '3em';

Handling events

To respond to external events such as clicks, changes of focus, andselections, add an event listener. You can add an event listener to anyelement on the page. Event dispatch and propagation is a complicatedsubject; research thedetailsif you’re new to web programming.

Add an event handler usingelement.onEvent.listen(function),where Event is the eventname and function is the event handler.

For example, here’s how you can handle clicks on a button:

// Find a button by ID and add an event handler.
querySelector('#submitInfo').onClick.listen((e) {
  // When the button is clicked, it runs this code.
  submitData();
});

Events can propagate up and down through the DOM tree. To discover whichelement originally fired the event, use e.target:

document.body.onClick.listen((e) {
  final clickedElem = e.target;
  // ...
});

To see all the events for which you can register an event listener, lookfor “onEventType” properties in the API docs for Element and itssubclasses. Some common events include:

  • change
  • blur
  • keyDown
  • keyUp
  • mouseDown
  • mouseUp

Using HTTP resources with HttpRequest

Formerly known as XMLHttpRequest, the HttpRequest classgives you access to HTTP resources from within your browser-based app.Traditionally, AJAX-style apps make heavy use of HttpRequest. UseHttpRequest to dynamically load JSON data or any other resource from aweb server. You can also dynamically send data to a web server.

Getting data from the server

The HttpRequest static method getString() is an easy way to get datafrom a web server. Use await with the getString() callto ensure that you have the data before continuing execution.

Future main() async {
  String pageHtml = await HttpRequest.getString(url);
  // Do something with pageHtml...
}

Use try-catch to specify an error handler:

try {
  var data = await HttpRequest.getString(jsonUri);
  // Process data...
} catch (e) {
  // Handle exception...
}

If you need access to the HttpRequest, not just the text data itretrieves, you can use the request() static method instead ofgetString(). Here’s an example of reading XML data:

Future main() async {
  HttpRequest req = await HttpRequest.request(
    url,
    method: 'HEAD',
  );
  if (req.status == 200) {
    // Successful URL access...
  }
  // ···
}

You can also use the full API to handle more interesting cases. Forexample, you can set arbitrary headers.

The general flow for using the full API of HttpRequest is as follows:

  • Create the HttpRequest object.
  • Open the URL with either GET or POST.
  • Attach event handlers.
  • Send the request.For example:
var request = HttpRequest();
request
  ..open('POST', url)
  ..onLoadEnd.listen((e) => requestComplete(request))
  ..send(encodedData);

Sending data to the server

HttpRequest can send data to the server using the HTTP method POST. Forexample, you might want to dynamically submit data to a form handler.Sending JSON data to a RESTful web service is another common example.

Submitting data to a form handler requires you to provide name-valuepairs as URI-encoded strings. (Information about the URI class is inthe URIs section of the Dart Library Tour.)You must also set the Content-type header toapplication/x-www-form-urlencode if you wish to send data to a formhandler.

String encodeMap(Map<String, String> data) => data.keys
    .map((k) => '${Uri.encodeComponent(k)}=${Uri.encodeComponent(data[k])}')
    .join('&');

Future main() async {
  var data = {'dart': 'fun', 'angular': 'productive'};

  var request = HttpRequest();
  request
    ..open('POST', url)
    ..setRequestHeader(
      'Content-type',
      'application/x-www-form-urlencoded',
    )
    ..send(encodeMap(data));

  await request.onLoadEnd.first;

  if (request.status == 200) {
    // Successful URL access...
  }
  // ···
}

Sending and receiving real-time data with WebSockets

A WebSocket allows your web app to exchange data with a serverinteractively—no polling necessary. A server creates the WebSocket andlistens for requests on a URL that starts with ws://—for example,ws://127.0.0.1:1337/ws. The data transmitted over a WebSocket can be astring or a blob. Often, the data is a JSON-formatted string.

To use a WebSocket in your web app, first create a WebSocket object, passingthe WebSocket URL as an argument:

var ws = WebSocket('ws://echo.websocket.org');

Sending data

To send string data on the WebSocket, use the send() method:

ws.send('Hello from Dart!');

Receiving data

To receive data on the WebSocket, register a listener for messageevents:

ws.onMessage.listen((MessageEvent e) {
  print('Received message: ${e.data}');
});

The message event handler receives a MessageEvent object.This object’s data field has the data from the server.

Handling WebSocket events

Your app can handle the following WebSocket events: open, close, error,and (as shown earlier) message. Here’s an example of a method thatcreates a WebSocket object and registers handlers for open, close,error, and message events:

void initWebSocket([int retrySeconds = 1]) {
  var reconnectScheduled = false;

  print("Connecting to websocket");

  void scheduleReconnect() {
    if (!reconnectScheduled) {
      Timer(Duration(seconds: retrySeconds),
          () => initWebSocket(retrySeconds * 2));
    }
    reconnectScheduled = true;
  }

  ws.onOpen.listen((e) {
    print('Connected');
    ws.send('Hello from Dart!');
  });

  ws.onClose.listen((e) {
    print('Websocket closed, retrying in ' + '$retrySeconds seconds');
    scheduleReconnect();
  });

  ws.onError.listen((e) {
    print("Error connecting to ws");
    scheduleReconnect();
  });

  ws.onMessage.listen((MessageEvent e) {
    print('Received message: ${e.data}');
  });
}

More information

This section barely scratched the surface of using the dart:htmllibrary. For more information, see the documentation fordart:html.Dart has additional libraries for more specialized web APIs, such asweb audio,IndexedDB, and WebGL.

For more information about Dart web libraries, see theweb library overview.

dart:io - I/O for servers and command-line apps

The dart:io library provides APIs to deal withfiles, directories, processes, sockets, WebSockets, and HTTPclients and servers.

Important: Only Flutter mobile apps, command-line scripts, and servers can import and use dart:io, not web apps.

In general, the dart:io library implements and promotes an asynchronousAPI. Synchronous methods can easily block an application, making itdifficult to scale. Therefore, most operations return results via Futureor Stream objects, a pattern common with modern server platforms such asNode.js.

The few synchronous methods in the dart:io library are clearly markedwith a Sync suffix on the method name. Synchronous methods aren’t covered here.

To use the dart:io library you must import it:

import 'dart:io';

Files and directories

The I/O library enables command-line apps to read and write files andbrowse directories. You have two choices for reading the contents of afile: all at once, or streaming. Reading a file all at once requiresenough memory to store all the contents of the file. If the file is verylarge or you want to process it while reading it, you should use aStream, as described inStreaming file contents.

Reading a file as text

When reading a text file encoded using UTF-8, you can read the entirefile contents with readAsString(). When the individual lines areimportant, you can use readAsLines(). In both cases, a Future objectis returned that provides the contents of the file as one or morestrings.

Future main() async {
  var config = File('config.txt');
  var contents;

  // Put the whole file in a single string.
  contents = await config.readAsString();
  print('The file is ${contents.length} characters long.');

  // Put each line of the file into its own string.
  contents = await config.readAsLines();
  print('The file is ${contents.length} lines long.');
}

Reading a file as binary

The following code reads an entire file as bytes into a list of ints.The call to readAsBytes() returns a Future, which provides the resultwhen it’s available.

Future main() async {
  var config = File('config.txt');

  var contents = await config.readAsBytes();
  print('The file is ${contents.length} bytes long.');
}

Handling errors

To capture errors so they don’t result in uncaught exceptions, you canregister a catchError handler on the Future,or (in an async function) use try-catch:

Future main() async {
  var config = File('config.txt');
  try {
    var contents = await config.readAsString();
    print(contents);
  } catch (e) {
    print(e);
  }
}

Streaming file contents

Use a Stream to read a file, a little at a time.You can use either the Stream APIor await for, part of Dart’sasynchrony support.

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

Future main() async {
  var config = File('config.txt');
  Stream<List<int>> inputStream = config.openRead();

  var lines =
      utf8.decoder.bind(inputStream).transform(LineSplitter());
  try {
    await for (var line in lines) {
      print('Got ${line.length} characters from stream');
    }
    print('file is now closed');
  } catch (e) {
    print(e);
  }
}

Writing file contents

You can use an IOSink towrite data to a file. Use the File openWrite() method to get an IOSinkthat you can write to. The default mode, FileMode.write, completelyoverwrites existing data in the file.

var logFile = File('log.txt');
var sink = logFile.openWrite();
sink.write('FILE ACCESSED ${DateTime.now()}\n');
await sink.flush();
await sink.close();

To add to the end of the file, use the optional mode parameter tospecify FileMode.append:

var sink = logFile.openWrite(mode: FileMode.append);

To write binary data, use add(List<int> data).

Listing files in a directory

Finding all files and subdirectories for a directory is an asynchronousoperation. The list() method returns a Stream that emits an objectwhen a file or directory is encountered.

Future main() async {
  var dir = Directory('tmp');

  try {
    var dirList = dir.list();
    await for (FileSystemEntity f in dirList) {
      if (f is File) {
        print('Found file ${f.path}');
      } else if (f is Directory) {
        print('Found dir ${f.path}');
      }
    }
  } catch (e) {
    print(e.toString());
  }
}

Other common functionality

The File and Directory classes contain other functionality, includingbut not limited to:

  • Creating a file or directory: create() in File and Directory
  • Deleting a file or directory: delete() in File and Directory
  • Getting the length of a file: length() in File
  • Getting random access to a file: open() in File

Refer to the API docs for File and Directory for a fulllist of methods.

HTTP clients and servers

The dart:io library provides classes that command-line apps can use foraccessing HTTP resources, as well as running HTTP servers.

HTTP server

The HttpServer classprovides the low-level functionality for building web servers. You canmatch request handlers, set headers, stream data, and more.

The following sample web server returns simple text information.This server listens on port 8888 and address 127.0.0.1 (localhost),responding to requests for the path /dart. For any other path,the response is status code 404 (page not found).

Future main() async {
  final requests = await HttpServer.bind('localhost', 8888);
  await for (var request in requests) {
    processRequest(request);
  }
}

void processRequest(HttpRequest request) {
  print('Got request for ${request.uri.path}');
  final response = request.response;
  if (request.uri.path == '/dart') {
    response
      ..headers.contentType = ContentType(
        'text',
        'plain',
      )
      ..write('Hello from the server');
  } else {
    response.statusCode = HttpStatus.notFound;
  }
  response.close();
}

HTTP client

The HttpClient classhelps you connect to HTTP resources from your Dart command-line orserver-side application. You can set headers, use HTTP methods, and readand write data. The HttpClient class does not work in browser-basedapps. When programming in the browser, use thedart:html HttpRequest class.Here’s an example of using HttpClient:

Future main() async {
  var url = Uri.parse('http://localhost:8888/dart');
  var httpClient = HttpClient();
  var request = await httpClient.getUrl(url);
  var response = await request.close();
  var data = await utf8.decoder.bind(response).toList();
  print('Response ${response.statusCode}: $data');
  httpClient.close();
}

More information

This page showed how to use the major features of the dart:io library.Besides the APIs discussed in this section, the dart:io library alsoprovides APIs for processes,sockets, andweb sockets.For more information about server-side and command-line app development, see theserver-side Dart overview.

For information on other dart:* libraries, see thelibrary tour.

Summary

This page introduced you to the most commonly used functionality inDart’s built-in libraries. It didn’t cover all the built-inlibraries, however. Others that you might want to look into includedart:collection and dart:typed_data,as well as platform-specific libaries like theDart web development librariesand the Flutter libraries.

You can get yet more libraries by using the pub package manager. Thecollection,crypto,http,intl, andtest libraries are just asampling of what you can install using pub.

To learn more about the Dart language, see thelanguage tour.