IO

IO #

dart:io adalah library bawaan Dart yang menyediakan akses ke input/output sistem operasi — file, direktori, socket, HTTP, proses, dan informasi platform. Artikel ini berfokus pada komponen dart:io yang belum dibahas mendalam di artikel I/O section Lanjutan: HttpClient bawaan Dart untuk membuat HTTP request langsung, InternetAddress untuk lookup DNS, NetworkInterface untuk informasi jaringan, stdin/stdout/stderr secara lengkap, Platform untuk informasi sistem, dan pengelolaan proses.

dart:io hanya tersedia di Dart VM — tidak bisa digunakan di kode yang dikompilasi ke JavaScript (web). Untuk Flutter web, gunakan dart:html atau package http yang portable.

Gambaran dart:io #

flowchart LR
    DIO["dart:io"] --> FILE["File & Directory\nFile, Directory, FileSystemEntity"]
    DIO --> NET["Networking\nSocket, HttpClient, HttpServer\nSecureSocket, WebSocket"]
    DIO --> PROC["Process\nProcess, ProcessSignal\nProcessResult"]
    DIO --> SYS["System\nPlatform, stdin, stdout\nstderr, exit, ProcessInfo"]
    DIO --> DNS["DNS & Network\nInternetAddress\nNetworkInterface"]

HttpClient — HTTP Request Bawaan Dart #

dart:io menyertakan HttpClient — HTTP client yang lebih tingkat rendah dari package http, memberikan kontrol penuh atas setiap aspek request:

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

Future<void> contohHttpClient() async {
  final client = HttpClient();

  try {
    // GET request
    final request = await client.getUrl(
      Uri.parse('https://api.example.com/produk'),
    );

    // Tambahkan header
    request.headers
      ..set('Authorization', 'Bearer mytoken')
      ..set('Accept', 'application/json')
      ..set(HttpHeaders.contentTypeHeader, 'application/json');

    // Kirim request dan tunggu response
    final response = await request.close();

    // Baca body response
    final body = await response.transform(utf8.decoder).join();

    print('Status: ${response.statusCode}');
    print('Content-Type: ${response.headers.contentType}');

    if (response.statusCode == HttpStatus.ok) {
      final data = jsonDecode(body);
      print(data);
    }

  } finally {
    client.close(); // tutup client setelah selesai
  }
}

POST dan Upload Data #

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

Future<Map<String, dynamic>> postData(
  String url,
  Map<String, dynamic> data,
) async {
  final client = HttpClient();

  try {
    final request = await client.postUrl(Uri.parse(url));
    request.headers
      ..contentType = ContentType.json
      ..set('Authorization', 'Bearer token');

    // Tulis body request
    final body = jsonEncode(data);
    request.contentLength = utf8.encode(body).length;
    request.write(body);

    final response = await request.close();
    final responseBody = await response.transform(utf8.decoder).join();

    if (response.statusCode >= 400) {
      throw HttpException(
        'Request gagal: ${response.statusCode}',
        uri: Uri.parse(url),
      );
    }

    return jsonDecode(responseBody) as Map<String, dynamic>;
  } finally {
    client.close();
  }
}

Konfigurasi HttpClient #

final client = HttpClient()
  // Timeout koneksi
  ..connectionTimeout = Duration(seconds: 10)
  // Maksimal koneksi per host (default: 6)
  ..maxConnectionsPerHost = 10
  // Ikuti redirect secara otomatis (default: true)
  ..autoUncompress = true
  // Konfigurasi proxy
  ..findProxy = (uri) => 'PROXY proxy.example.com:8080'
  // Verifikasi sertifikat SSL — JANGAN nonaktifkan di produksi!
  ..badCertificateCallback =
      (X509Certificate cert, String host, int port) => false; // false = reject

Perbandingan HttpClient vs Package http #

// dart:io HttpClient — tingkat rendah, lebih banyak kontrol
final request = await client.getUrl(uri);
request.headers.set('X-Custom', 'value');
final response = await request.close();
final body = await response.transform(utf8.decoder).join();

// Package http — lebih sederhana, lebih idiomatis
import 'package:http/http.dart' as http;
final response = await http.get(uri, headers: {'X-Custom': 'value'});
final body = response.body;

// Gunakan package http kecuali butuh kontrol sangat spesifik

InternetAddress — DNS dan Alamat IP #

import 'dart:io';

Future<void> contohInternetAddress() async {
  // Lookup DNS — resolve hostname ke IP address
  final addresses = await InternetAddress.lookup('dart.dev');
  for (final addr in addresses) {
    print('${addr.host}: ${addr.address} (${addr.type.name})');
    // dart.dev: 35.219.196.5 (InternetAddressType.IPv4)
  }

  // Lookup reverse — IP ke hostname
  final reverseResult = await InternetAddress('8.8.8.8').reverse();
  print('8.8.8.8 → ${reverseResult.host}'); // dns.google

  // Tipe alamat
  final ipv4 = InternetAddress('192.168.1.1');
  final ipv6 = InternetAddress('::1');
  final loopback4 = InternetAddress.loopbackIPv4; // 127.0.0.1
  final loopback6 = InternetAddress.loopbackIPv6; // ::1
  final any4 = InternetAddress.anyIPv4;           // 0.0.0.0
  final any6 = InternetAddress.anyIPv6;           // ::

  print(ipv4.type.name);        // InternetAddressType.IPv4
  print(ipv6.type.name);        // InternetAddressType.IPv6
  print(ipv4.isLoopback);       // false
  print(loopback4.isLoopback);  // true
  print(ipv4.isMulticast);      // false
  print(ipv4.rawAddress);       // Uint8List dari bytes IP
}

NetworkInterface — Informasi Jaringan Lokal #

import 'dart:io';

Future<void> infoJaringan() async {
  // Dapatkan semua network interface di mesin ini
  final interfaces = await NetworkInterface.list(
    includeLoopback: false,        // abaikan 127.0.0.1/::1
    includeLinkLocal: false,       // abaikan link-local (169.254.x.x)
    type: InternetAddressType.any, // IPv4 dan IPv6
  );

  for (final iface in interfaces) {
    print('\nInterface: ${iface.name}'); // eth0, en0, wlan0, dll.
    print('Index: ${iface.index}');

    for (final addr in iface.addresses) {
      print('  ${addr.address} (${addr.type.name})');
      print('  Loopback: ${addr.isLoopback}');
      print('  Multicast: ${addr.isMulticast}');
    }
  }
}

// Dapatkan IP lokal mesin untuk ditampilkan ke pengguna
Future<String?> dapatIPLokal() async {
  final interfaces = await NetworkInterface.list(
    includeLoopback: false,
    type: InternetAddressType.IPv4,
  );

  for (final iface in interfaces) {
    for (final addr in iface.addresses) {
      if (!addr.isLoopback && !addr.isMulticast) {
        return addr.address;
      }
    }
  }
  return null;
}

stdin, stdout, stderr — Standard I/O Mendalam #

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

// stdout — output standar
stdout.write('Tanpa newline: ');
stdout.writeln('Dengan newline');
stdout.writeAll(['a', 'b', 'c'], ', '); // 'a, b, c'

// print() adalah shortcut untuk stdout.writeln()
print('Sama dengan stdout.writeln()');

// stderr — output error (stream terpisah dari stdout)
stderr.writeln('ERROR: Sesuatu yang salah terjadi');
// Berguna karena stderr bisa di-redirect terpisah dari stdout:
// dart run script.dart 2>error.log

// stdin — input standar
// Membaca satu baris (sinkron — ok untuk CLI)
stdout.write('Masukkan nama: ');
final nama = stdin.readLineSync();
print('Halo, $nama!');

// Membaca dengan encoding tertentu
final namaUtf8 = stdin.readLineSync(encoding: utf8);

// stdin sebagai Stream (untuk data piped)
// echo "data" | dart run script.dart
await stdin
    .transform(utf8.decoder)
    .transform(const LineSplitter())
    .forEach((baris) {
      print('Diterima: $baris');
    });

// Cek apakah stdin memiliki data (untuk deteksi pipe vs terminal)
print('stdin is terminal: ${stdin.hasTerminal}');
print('stdout is terminal: ${stdout.hasTerminal}');

// Atur encoding
stdin.encoding = utf8;
stdout.encoding = utf8;

CLI Interaktif yang Lebih Baik #

import 'dart:io';

class CLI {
  // Baca input dengan prompt dan validasi
  static String baca(
    String prompt, {
    bool wajib = true,
    String? Function(String)? validasi,
  }) {
    while (true) {
      stdout.write(prompt);
      final input = stdin.readLineSync()?.trim() ?? '';

      if (wajib && input.isEmpty) {
        stderr.writeln('Input tidak boleh kosong.');
        continue;
      }

      final error = validasi?.call(input);
      if (error != null) {
        stderr.writeln('Error: $error');
        continue;
      }

      return input;
    }
  }

  // Baca angka
  static int bacaInt(String prompt, {int? min, int? max}) {
    return int.parse(baca(
      prompt,
      validasi: (s) {
        final n = int.tryParse(s);
        if (n == null) return 'Masukkan angka yang valid';
        if (min != null && n < min) return 'Minimum: $min';
        if (max != null && n > max) return 'Maksimum: $max';
        return null;
      },
    ));
  }

  // Konfirmasi ya/tidak
  static bool konfirmasi(String prompt) {
    final input = baca('$prompt (y/n): ').toLowerCase();
    return input == 'y' || input == 'ya' || input == 'yes';
  }

  // Pilih dari menu
  static int pilihMenu(String judul, List<String> pilihan) {
    stdout.writeln('\n=== $judul ===');
    for (int i = 0; i < pilihan.length; i++) {
      stdout.writeln('${(i + 1).toString().padLeft(2)}. ${pilihan[i]}');
    }

    return bacaInt('Pilih (1-${pilihan.length}): ',
        min: 1, max: pilihan.length);
  }
}

// Penggunaan
void main() {
  final nama = CLI.baca('Nama: ');
  final umur = CLI.bacaInt('Umur: ', min: 1, max: 150);
  final konfirm = CLI.konfirmasi('Simpan data?');

  final pilihan = CLI.pilihMenu('Pilih aksi', ['Simpan', 'Edit', 'Hapus', 'Batal']);
  print('Pilihan: $pilihan');
}

Platform — Informasi Sistem #

import 'dart:io';

void infoSistem() {
  // Sistem operasi
  print(Platform.operatingSystem);        // 'linux', 'macos', 'windows', 'android', 'ios'
  print(Platform.operatingSystemVersion); // 'Linux 5.15.0-...' atau 'macOS 14.x...'
  print(Platform.localHostname);          // 'my-laptop' atau 'DESKTOP-ABC123'
  print(Platform.localeName);            // 'en_US.UTF-8' atau 'id_ID.UTF-8'
  print(Platform.numberOfProcessors);    // jumlah CPU logical core
  print(Platform.pathSeparator);         // '/' di Unix, '\' di Windows

  // Boolean shortcuts
  print(Platform.isLinux);     // true/false
  print(Platform.isMacOS);     // true/false
  print(Platform.isWindows);   // true/false
  print(Platform.isAndroid);   // true/false (hanya di Flutter)
  print(Platform.isIOS);       // true/false (hanya di Flutter)
  print(Platform.isFuchsia);   // true/false

  // Environment variables
  final home = Platform.environment['HOME'];           // Unix
  final userProfile = Platform.environment['USERPROFILE']; // Windows
  final path = Platform.environment['PATH'];
  final dbUrl = Platform.environment['DATABASE_URL'] ?? 'postgresql://localhost/mydb';

  // Informasi runtime Dart
  print(Platform.version);       // '3.x.x (stable) ...'
  print(Platform.executable);    // path ke executable Dart
  print(Platform.script);        // URI script yang sedang berjalan
  print(Platform.executableArguments); // argumen ke Dart VM
  print(Platform.packageConfig);       // path ke .dart_tool/package_config.json

  // Argumen ke script dari command line
  // dart run script.dart arg1 arg2 --flag
  print(Platform.executableArguments); // argumen ke dart
  // argumen ke script diakses via void main(List<String> args)
}

// Pola umum: konfigurasi berbeda per platform
String getDatabasePath() {
  if (Platform.isWindows) {
    return '${Platform.environment['APPDATA']}\\MyApp\\database.db';
  } else if (Platform.isMacOS) {
    return '${Platform.environment['HOME']}/Library/Application Support/MyApp/database.db';
  } else {
    return '${Platform.environment['HOME']}/.local/share/MyApp/database.db';
  }
}

ProcessInfo — Informasi Proses #

import 'dart:io';

void infoProses() {
  // Penggunaan memori saat ini
  final meminfo = ProcessInfo.currentRss;     // RSS (Resident Set Size) dalam bytes
  final maxMem = ProcessInfo.maxRss;          // maksimal RSS yang pernah dicapai

  print('Memori saat ini: ${meminfo ~/ 1024 ~/ 1024} MB');
  print('Memori maksimal: ${maxMem ~/ 1024 ~/ 1024} MB');
}

// Monitor memori secara berkala (untuk debugging memory leak)
void monitorMemori({Duration interval = const Duration(seconds: 5)}) {
  Timer.periodic(interval, (_) {
    final rss = ProcessInfo.currentRss;
    final mb = rss / 1024 / 1024;
    print('[${DateTime.now()}] Memori: ${mb.toStringAsFixed(1)} MB');
  });
}

exit dan Signal Handling #

import 'dart:io';

void main() async {
  // Tangani sinyal untuk graceful shutdown
  ProcessSignal.sigint.watch().listen((signal) async {
    print('\nMenerima SIGINT, membersihkan resource...');
    await bersihkan();
    exit(0); // kode 0 = sukses
  });

  ProcessSignal.sigterm.watch().listen((signal) async {
    print('Menerima SIGTERM, shutdown graceful...');
    await bersihkan();
    exit(0);
  });

  // Jalankan aplikasi
  await jalankan();
}

Future<void> bersihkan() async {
  // Tutup koneksi database, flush log, dll.
  print('Koneksi ditutup, log di-flush');
}

// Exit codes konvensional
// exit(0) — sukses
// exit(1) — error umum
// exit(2) — misuse of shell/command (argumen tidak valid)
// exit(126) — perintah tidak bisa dieksekusi
// exit(127) — perintah tidak ditemukan
// exit(130) — script dihentikan oleh Ctrl+C

// Keluar dengan kode error
void handleError(String pesan) {
  stderr.writeln('FATAL ERROR: $pesan');
  exit(1);
}

Stdin — Mode Raw #

import 'dart:io';

// Mode raw — baca setiap keystroke tanpa menunggu Enter
// Berguna untuk game CLI atau aplikasi interaktif
Future<void> modeRaw() async {
  stdin.echoMode = false;  // jangan tampilkan karakter yang diketik
  stdin.lineMode = false;  // baca per karakter, bukan per baris

  try {
    stdout.writeln('Tekan tombol (q untuk keluar):');

    await stdin.forEach((bytes) {
      for (final byte in bytes) {
        if (byte == 113) { // 'q'
          stdout.writeln('\nKeluar');
          exit(0);
        }
        stdout.write('Kode: $byte (${String.fromCharCode(byte)})\n');
      }
    });
  } finally {
    stdin.echoMode = true;   // restore mode
    stdin.lineMode = true;
  }
}

Referensi Cepat — Kelas Utama dart:io #

Kelas Deskripsi
File Baca/tulis file
Directory Operasi direktori
HttpClient HTTP client
HttpServer HTTP server
Socket TCP socket
ServerSocket TCP server socket
SecureSocket TLS/SSL socket
WebSocket WebSocket client/server
RawDatagramSocket UDP socket
InternetAddress Alamat IP dan DNS lookup
NetworkInterface Info network interface
Process Jalankan proses eksternal
ProcessSignal Handle OS signal
ProcessInfo Info memori proses
Platform Info platform/OS
stdin Standard input stream
stdout Standard output stream
stderr Standard error stream
exit() Keluar dengan kode
sleep() Pause synchronous

Ringkasan #

  • dart:io hanya di Dart VM — tidak tersedia di Flutter web. Gunakan package:http yang portable untuk HTTP di semua platform.
  • HttpClient bawaan memberikan kontrol penuh atas HTTP — timeout, proxy, header, redirect — tapi lebih verbose dari package:http. Gunakan package:http kecuali butuh kontrol spesifik.
  • InternetAddress.lookup() untuk resolve DNS — mengembalikan semua alamat IP (IPv4 dan IPv6) untuk hostname tertentu. Gunakan .reverse() untuk PTR lookup.
  • NetworkInterface.list() untuk mendapatkan IP lokal mesin — berguna untuk menampilkan alamat server kepada pengguna.
  • stdin.hasTerminal untuk deteksi apakah program dijalankan interaktif atau via pipe — berguna untuk menentukan apakah harus menampilkan prompt atau langsung membaca data.
  • stderr untuk pesan error dan diagnostik — terpisah dari stdout sehingga bisa di-redirect secara independen: dart run script.dart 2>error.log.
  • stdin.echoMode = false + stdin.lineMode = false untuk baca input per karakter tanpa menunggu Enter — berguna untuk CLI interaktif dan game.
  • Platform.environment adalah cara idiomatis membaca konfigurasi dari environment variable — standar untuk 12-factor app.
  • ProcessSignal.sigint.watch() untuk graceful shutdown — tangani Ctrl+C dengan bersih, tutup semua resource sebelum keluar.
  • exit(0) untuk sukses, exit(1) untuk error — kode exit dikonsumsi oleh shell script dan CI/CD untuk menentukan apakah program berhasil.

← Sebelumnya: Strings   Berikutnya: Math →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact