Setiap pemanggilan Read dan Write yang sampai ke sistem operasi punya harga: operasi tersebut relatif lambat dibanding kerja di memori. Package bufio menyisipkan lapisan penyangga (buffer) di antara program dan sumber data, sehingga banyak bacaan kecil digabung menjadi sedikit operasi besar. Chapter ini membedah tiga perangkat utamanya — Reader, Writer, dan Scanner — lengkap dengan jebakan Flush yang paling sering menggigit pemula.

bufio.Reader: Membaca sampai Delimiter #

bufio.NewReader membungkus io.Reader mana pun dan menambahkan penyangga internal. Method ReadString('\n') membaca sampai delimiter ditemukan lalu mengembalikan seluruh teks termasuk delimiter-nya, sehingga tanda baris baru ikut dalam hasil. Gunakan strings.TrimSuffix bila tanda baris baru tidak diinginkan di dalam hasil.

ReadString hanyalah satu dari beberapa method pembaca: ReadBytes mengembalikan []byte, ReadByte satu byte, dan ReadRune satu karakter Unicode. Ketiga method tersebut membaca dari penyangga, bukan langsung dari sumber — itulah sumber kecepatannya. Method Reset mengosongkan state Reader agar penyangga yang sama bisa dipakai ulang untuk sumber baru.

bufio.Writer dan Kewajiban Flush #

bufio.NewWriter bekerja secara terbalik: tulisan dikumpulkan di penyangga, dan hanya dikirim ke tujuan ketika penyangga penuh atau ketika Flush dipanggil. Method Flush wajib ada di akhir rangkaian penulisan:

bufio.Scanner: Baris demi Baris #

Untuk teks berformat baris, Scanner lebih ringkas daripada Reader. Loop for pemindai.Scan() mengembalikan satu baris per iterasi, Text() mengambil isinya tanpa tanda baris baru, dan akhir input menghentikan loop tanpa error yang perlu diperiksa — kesalahan sungguhan (misalnya baris terlalu panjang) diambil lewat pemindai.Err() setelah loop selesai.

Perilaku keduanya berbeda cukup besar untuk menentukan pilihan:

Aspekbufio.Readerbufio.Scanner
Unit bacabyte, rune, atau sampai delimiter bebasbaris, atau token sesuai fungsi Split
Delimiterikut dalam hasil bacaandibuang dari token
Errordikembalikan setiap pemanggilan, io.EOF eksplisitakhir data dianggap selesai; cek Err()
Cocok untukprotokol biner, delimiter tak standarteks baris demi baris, log, CSV sederhana

Program Utuh #

Berkas bufio-demo.go mempraktikkan ketiga perangkat dengan strings.NewReader sebagai sumber:

go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	// bufio.Reader membaca sampai delimiter yang kita pilih.
	pembaca := bufio.NewReader(strings.NewReader("nama:Budi\numur:25\n"))
	nama, _ := pembaca.ReadString('\n')
	umur, _ := pembaca.ReadString('\n')
	fmt.Printf("readstring: %q | %q\n", nama, umur)

	// bufio.Writer menampung tulisan lalu mengirimkannya saat Flush.
	penulis := bufio.NewWriter(os.Stdout)
	penulis.WriteString("baris lewat bufio.Writer\n")
	penulis.WriteString("baru terlihat setelah Flush\n")
	penulis.Flush()

	// bufio.Scanner memecah input menjadi baris.
	pemindai := bufio.NewScanner(strings.NewReader("ayam\nbebek\nkambing\n"))
	for pemindai.Scan() {
		fmt.Println("baris:", pemindai.Text())
	}

	// Scanner dengan pemisah kata.
	kata := bufio.NewScanner(strings.NewReader("belajar bufio itu mudah"))
	kata.Split(bufio.ScanWords)
	var daftar []string
	for kata.Scan() {
		daftar = append(daftar, kata.Text())
	}
	fmt.Println("kata:", strings.Join(daftar, "/"))
}

Jalankan program dari folder chapter:

bash
go run bufio-demo.go

Output yang Dihasilkan:

text
readstring: "nama:Budi\n" | "umur:25\n"
baris lewat bufio.Writer
baru terlihat setelah Flush
baris: ayam
baris: bebek
baris: kambing
kata: belajar/bufio/itu/mudah

Mari kita telaah baris demi baris program di atas:

  1. Baris 12-15: dua kali ReadString('\n') membaca pasangan kunci-nilai; verb %q memperlihatkan bahwa tanda \n ikut di dalam hasil — bukti visual perilaku Reader.
  2. Baris 18-21: bufio.NewWriter(os.Stdout) membuat penulis bersangga; dua baris teks ditulis tanpa langsung muncul, lalu Flush pada baris 21 mengirim semuanya.
  3. Baris 24-27: Scanner memecah tiga baris teks; Scan() maju satu baris dan Text() mengambil isinya tanpa tanda baris baru.
  4. Baris 30-31: Scanner kedua memakai kata.Split(bufio.ScanWords) sehingga token-nya berupa kata, bukan baris.
  5. Baris 32-36: setiap kata dikumpulkan ke daftar lalu digabung dengan pemisah / agar hasil pemecahan terlihat jelas.

Token Kata dan Batas Penyangga #

Fungsi Split menentukan cara Scanner memotong input: ScanLines (bawaan), ScanWords, atau fungsi buatan sendiri. Scanner juga menyimpan token di penyangga internal yang ukurannya dibatasi — secara bawaan 64 KB per token. Baris log panjang atau data CSV yang melebihi batas membuat Scan() berhenti dan Err() melaporkan bufio.ErrTooLong. Perbesar kapasitasnya sebelum loop dimulai:

go
pemindai := bufio.NewScanner(berkas)
pemindai.Buffer(make([]byte, 64*1024), 1024*1024)

bufio.Reader punya kendali serupa lewat bufio.NewReaderSize(r, ukuran) ketika penyangga bawaan 4096 byte kurang pas. Untuk memproses berkas jutaan baris tanpa memuat semuanya ke memori, pola Scanner ini dibahas tuntas di chapter Handling Large File .

Referensi #

Dengan bufio, baca-tulis teks menjadi cepat dan nyaman. Chapter berikutnya tetap di wilayah data: package filepath dan path yang merangkai alamat berkas dengan aman di semua sistem operasi.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

bufio-demo.go

Unduh berkas
go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	// bufio.Reader membaca sampai delimiter yang kita pilih.
	pembaca := bufio.NewReader(strings.NewReader("nama:Budi\numur:25\n"))
	nama, _ := pembaca.ReadString('\n')
	umur, _ := pembaca.ReadString('\n')
	fmt.Printf("readstring: %q | %q\n", nama, umur)

	// bufio.Writer menampung tulisan lalu mengirimkannya saat Flush.
	penulis := bufio.NewWriter(os.Stdout)
	penulis.WriteString("baris lewat bufio.Writer\n")
	penulis.WriteString("baru terlihat setelah Flush\n")
	penulis.Flush()

	// bufio.Scanner memecah input menjadi baris.
	pemindai := bufio.NewScanner(strings.NewReader("ayam\nbebek\nkambing\n"))
	for pemindai.Scan() {
		fmt.Println("baris:", pemindai.Text())
	}

	// Scanner dengan pemisah kata.
	kata := bufio.NewScanner(strings.NewReader("belajar bufio itu mudah"))
	kata.Split(bufio.ScanWords)
	var daftar []string
	for kata.Scan() {
		daftar = append(daftar, kata.Text())
	}
	fmt.Println("kata:", strings.Join(daftar, "/"))
}