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:iohanya tersedia di Dart VM — tidak bisa digunakan di kode yang dikompilasi ke JavaScript (web). Untuk Flutter web, gunakandart:htmlatau packagehttpyang 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:iohanya di Dart VM — tidak tersedia di Flutter web. Gunakanpackage:httpyang portable untuk HTTP di semua platform.HttpClientbawaan memberikan kontrol penuh atas HTTP — timeout, proxy, header, redirect — tapi lebih verbose daripackage:http. Gunakanpackage:httpkecuali 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.hasTerminaluntuk deteksi apakah program dijalankan interaktif atau via pipe — berguna untuk menentukan apakah harus menampilkan prompt atau langsung membaca data.stderruntuk pesan error dan diagnostik — terpisah daristdoutsehingga bisa di-redirect secara independen:dart run script.dart 2>error.log.stdin.echoMode = false+stdin.lineMode = falseuntuk baca input per karakter tanpa menunggu Enter — berguna untuk CLI interaktif dan game.Platform.environmentadalah 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.