Saltar al contenido principal

dart:io

Aprende sobre las características principales de la biblioteca dart:io de Dart.

La biblioteca dart:io proporciona APIs para trabajar con archivos, directorios, procesos, sockets, WebSockets y clientes y servidores HTTP.

En general, la biblioteca dart:io implementa y promueve una API asíncrona. Los métodos síncronos pueden bloquear fácilmente una aplicación, lo que dificulta su escalabilidad. Por lo tanto, la mayoría de las operaciones devuelven resultados a través de objetos Future o Stream, un patrón común en plataformas de servidor modernas como Node.js.

Los pocos métodos síncronos en la biblioteca dart:io están claramente marcados con el sufijo Sync en el nombre del método. Los métodos síncronos no se cubren aquí.

Para usar la biblioteca dart:io debes importarla:

dart
import 'dart:io';

Archivos y directorios

#

La biblioteca de E/S permite que las aplicaciones de línea de comandos lean y escriban archivos y exploren directorios. Tienes dos opciones para leer el contenido de un archivo: todo a la vez, o mediante streaming. Leer un archivo todo a la vez requiere suficiente memoria para almacenar todo el contenido del archivo. Si el archivo es muy grande o deseas procesarlo mientras lo lees, deberías usar un Stream, como se describe en Streaming de contenido de archivos.

Lectura de un archivo como texto

#

Al leer un archivo de texto codificado usando UTF-8, puedes leer todo el contenido del archivo con readAsString(). Cuando las líneas individuales son importantes, puedes usar readAsLines(). En ambos casos, se devuelve un objeto Future que proporciona el contenido del archivo como una o más cadenas.

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

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

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

Lectura de un archivo como binario

#

El siguiente código lee un archivo completo como bytes en una lista de enteros. La llamada a readAsBytes() devuelve un Future, que proporciona el resultado cuando está disponible.

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

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

Manejo de errores

#

Para capturar errores y evitar que resulten en excepciones no controladas, puedes registrar un manejador catchError en el Future, o (en una función async) usar try-catch:

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

Streaming de contenido de archivos

#

Usa un Stream para leer un archivo poco a poco. Puedes usar la API de Stream o bien await for, que forma parte del soporte de asincronía de Dart.

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

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

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

Escritura de contenido de archivos

#

Puedes usar un IOSink para escribir datos en un archivo. Usa el método openWrite() de File para obtener un IOSink en el que puedas escribir. El modo predeterminado, FileMode.write, sobrescribe por completo los datos existentes en el archivo.

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

Para añadir contenido al final del archivo, usa el parámetro opcional mode para especificar FileMode.append:

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

Para escribir datos binarios, usa add(List<int> data).

Listar archivos en un directorio

#

Buscar todos los archivos y subdirectorios de un directorio es una operación asíncrona. El método list() devuelve un Stream que emite un objeto cuando se encuentra un archivo o directorio.

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

  try {
    var dirList = dir.list();
    await for (final 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());
  }
}

Otra funcionalidad común

#

Las clases File y Directory contienen otra funcionalidad, que incluye pero no se limita a:

  • Crear un archivo o directorio: create() en File y Directory
  • Eliminar un archivo o directorio: delete() en File y Directory
  • Obtener la longitud de un archivo: length() en File
  • Obtener acceso aleatorio a un archivo: open() en File

Consulta la documentación de la API de File y Directory para ver la lista completa de métodos.

Clientes y servidores HTTP

#

La biblioteca dart:io proporciona clases que las aplicaciones de línea de comandos pueden usar para acceder a recursos HTTP, así como para ejecutar servidores HTTP.

Servidor HTTP

#

La clase HttpServer proporciona la funcionalidad de bajo nivel para construir servidores web. Puedes hacer coincidir manejadores de solicitudes, establecer cabeceras, transmitir datos (stream) y más.

El siguiente servidor web de ejemplo devuelve información de texto simple. Este servidor escucha en el puerto 8888 y en la dirección 127.0.0.1 (localhost), respondiendo a las solicitudes para la ruta /dart. Para cualquier otra ruta, la respuesta es el código de estado 404 (página no encontrada).

dart
void main() async {
  final requests = await HttpServer.bind('localhost', 8888);
  await for (final 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();
}

Cliente HTTP

#

Deberías evitar usar directamente dart:io para realizar solicitudes HTTP. La clase HttpClient en dart:io depende de la plataforma y está vinculada a una única implementación. En su lugar, usa una biblioteca de nivel superior como package:http.

El tutorial Fetch data from the internet explica cómo realizar solicitudes HTTP usando package:http.

Más información

#

Esta página mostró cómo usar las características principales de la biblioteca dart:io . Además de las APIs analizadas en esta sección, la biblioteca dart:io también proporciona APIs para procesos, sockets y web sockets. Para más información sobre el desarrollo de aplicaciones en el lado del servidor y de línea de comandos, consulta la visión general de Dart en el servidor.