Episode ini membedah interaksi dengan sistem file dan data formats: File.read, File.write, File.open dengan block, streaming file besar, class Pathname yang menjadi core class sejak Ruby 4.0, serta serialisasi JSON, YAML, CSV, dan Marshal.

Hampir setiap aplikasi berinteraksi dengan sistem file: menulis log, membaca konfigurasi, atau memproses data batch. Ruby menyediakan lapisan I/O yang nyaman melalui class File dan Pathname, ditambah library standar untuk berbagai format data. Kemampuan ini menjadi dasar untuk job background, importer data, dan operasi administrasi.
Episode 9 ini membedah dua area: file I/O — File.read, File.write, File.open dengan block, streaming untuk file besar, dan Pathname yang kini menjadi core class sejak Ruby 4.0 — serta data formats — JSON, YAML, CSV, dan Marshal untuk serialisasi biner. Siapkan direktori kerja kosong agar contohnya aman dijalankan.
Untuk kebutuhan sederhana, Ruby menyediakan helper satu baris:
printf 'Halo Ruby\nbaris kedua\n' > catatan.txtLalu baca dan tulis dari Ruby:
File.write("catatan2.txt", "Halo Ruby\n")
isi = File.read("catatan2.txt")
puts isiFile.write("catatan2.txt", "Halo Ruby\n") menulis string ke file (membuat atau menimpanya), dan File.read("catatan2.txt") membaca seluruh isi sebagai satu string. Untuk menambah ke akhir file tanpa menimpa, gunakan mode "a" pada File.open. Kedua helper ini menangani pembukaan dan penutupan file secara otomatis.
Ketika butuh kontrol lebih — mode, buffering, atau memastikan file selalu ditutup — pakai File.open dengan block. Keuntungan utamanya: file otomatis ditutup bahkan jika terjadi exception:
File.open("catatan2.txt", "a") do |file|
file.puts "Baris tambahan"
endBlock File.open("catatan2.txt", "a") do |file| membuka file dalam mode append. Method puts pada objek file menulis satu baris, dan setelah block selesai, Ruby menutup file otomatis. Pola ini adalah best practice untuk semua operasi file yang membutuhkan state tambahan.
Membaca file besar sekaligus dengan File.read bisa menghabiskan memori. Untuk memproses baris demi baris, gunakan File.foreach yang bersifat streaming — hanya satu baris yang dimuat ke memori setiap kali:
File.foreach("data.log") do |baris|
next if baris.strip.empty?
puts "Panjang: #{baris.length}"
endFile.foreach("data.log") do |baris| membaca data.log baris per baris tanpa memuat seluruh file. Kontrol next if baris.strip.empty? melewati baris kosong. Pola ini ideal untuk log berukuran gigabyte atau file CSV impor yang tidak mungkin dibaca sekaligus.
Pathname kini menjadi core class sejak Ruby 4.0 (sebelumnya stdlib). Class ini membungkus path string dengan method berorientasi objek, menggantikan manipulasi string yang rawan error:
require "pathname"
pn = Pathname.new("/var/log/app")
puts pn.join("app.log")
puts pn.directory?
puts pn.expand_pathPathname.new("/var/log/app") membuat objek path, pn.join("app.log") menggabungkan segmen path dengan aman, pn.directory? mengecek apakah path menunjuk direktori, dan expand_path mengubahnya menjadi path absolut. Karena kini core class, tidak perlu menambah dependency terpisah untuk kemampuan ini.
JSON adalah format pertukaran data utama untuk API. Sejak Ruby 3.4, parsing JSON memakai parser native yang membuatnya sekitar 1,5 kali lebih cepat:
require "json"
data = { nama: "Arman", skill: ["ruby", "rails"] }
json = JSON.generate(data)
puts json
puts JSON.parse(json)["nama"]JSON.generate(data) mengubah hash menjadi string JSON, dan JSON.parse(json) mengubahnya kembali menjadi hash. Catatan: hasil parse selalu menggunakan key string ("nama"), bukan simbol — perbedaan dengan literal hash yang perlu diingat saat mengakses data.
YAML umum dipakai untuk konfigurasi (misalnya konfigurasi aplikasi dan CI), sementara CSV untuk data tabular. Keduanya ada di stdlib:
require "csv"
File.write("data.csv", "nama,umur\nArman,30\nRuby,25\n")
CSV.foreach("data.csv", headers: true) do |baris|
puts "#{baris["nama"]} berumur #{baris["umur"]}"
endCSV.foreach("data.csv", headers: true) do |baris| membaca setiap baris sebagai hash ber-identitas kolom. Mengakses baris["nama"] jauh lebih terbaca daripada index angka. YAML di-load dengan YAML.load_file("config.yml"), yang mengembalikan struktur Ruby langsung.
Marshal adalah serialisasi biner bawaan Ruby untuk struktur data yang hanya dipakai oleh Ruby (misalnya cache internal). Ia sangat cepat, tetapi tidak aman untuk data dari sumber yang tidak dipercaya — kita akan bahas risikonya di episode 15:
data = { kunci: [1, 2, 3] }
File.binwrite("data.bin", Marshal.dump(data))
puts Marshal.load(File.binread("data.bin"))Marshal.dump(data) mengubah hash menjadi byte biner, dan Marshal.load memulihkannya. Karena formatnya spesifik versi Ruby, Marshal tidak cocok untuk pertukaran antar bahasa — gunakan JSON untuk itu.
Info
Pilih format berdasarkan kebutuhan: JSON untuk API dan pertukaran antar bahasa, YAML untuk konfigurasi yang mudah dibaca manusia, CSV untuk data tabular, dan Marshal hanya untuk data Ruby internal yang sudah dipercaya asalnya.
Episode 9 membekali kalian dengan keterampilan I/O: membaca dan menulis file dengan File.read, File.write, dan File.open dengan block, streaming file besar dengan File.foreach, class Pathname yang kini core class, serta serialisasi JSON, YAML, CSV, dan Marshal.
Inti yang harus dibawa pulang:
File.read dan File.write untuk operasi sederhana; File.open dengan block menutup file otomatis.File.foreach memproses file besar baris per baris tanpa memuat seluruhnya ke memori.Pathname adalah core class sejak Ruby 4.0 untuk manipulasi path berorientasi objek.JSON.parse menghasilkan key string, bukan simbol.Di episode 10 selanjutnya kita akan membahas collections: array, hash, range, dan set — operasi umum array dan hash, sorting dan transforming, default value hash, Enumerator dan Enumerator::Lazy untuk data besar, method next dan peek, Enumerator.produce, serta Set yang menjadi core class sejak Ruby 4.0. Ini inti pengelolaan data di Ruby.