Paket os menyediakan akses ke sistem berkas dan lingkungan proses, sedangkan paket io menyediakan kontrak aliran data berupa interface io.Reader dan io.Writer. Topik ini membahas pembuatan, penulisan, dan pembacaan berkas dengan kedua paket tersebut, kemudian menunjukkan bagaimana fungsi seperti io.Copy menyambungkan sembarang pembaca ke sembarang penulis tanpa mengetahui sumber sebenarnya. Contohnya berupa arsip cadangan berkas teks yang ditulis ke folder /tmp, sehingga program dapat dijalankan berulang tanpa meninggalkan berkas pada folder proyek. Setelah membacanya, operasi berkas dan komposisi aliran data dapat ditulis dengan pola yang benar beserta penanganan errornya.
Menulis dan membaca berkas#
Fungsi os.WriteFile menulis seluruh isi []byte ke satu berkas dalam satu panggilan, sedangkan os.ReadFile membaca seluruh isinya dan mengembalikan []byte. Panggilan os.WriteFile menerima izin berkas yang dipakai ketika berkasnya dibuat, misalnya 0o644 yang berarti pemiliknya boleh membaca dan menulis, sedangkan pengguna lain hanya membaca. Folder penampungnya wajib ada lebih dahulu, dan os.MkdirAll membuat folder beserta seluruh induknya bila belum ada. Setiap fungsi pada os mengembalikan error yang menyatakan penyebab kegagalan, misalnya izin yang tidak cukup atau folder yang tidak ditemukan. Program berikut membuat folder latihan, menulis satu berkas arsip, kemudian membacanya kembali.
package main
import (
"fmt"
"os"
)
func main() {
folder := "/tmp/gopustaka/io"
if err := os.MkdirAll(folder, 0o755); err != nil {
fmt.Println("error:", err)
return
}
jalur := folder + "/arsip.txt"
tulisan := []byte("arsip cadangan: 3 berkas tersalin\n")
if err := os.WriteFile(jalur, tulisan, 0o644); err != nil {
fmt.Println("error:", err)
return
}
isi, err := os.ReadFile(jalur)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("dibaca %d byte:\n%s", len(isi), isi)
}dibaca 34 byte:
arsip cadangan: 3 berkas tersalinPasangan WriteFile dan ReadFile cocok untuk berkas berukuran kecil yang isinya dimuat sekaligus di memori. Perhatikan bahwa ReadFile mengembalikan dua nilai, yaitu isi dan error, sehingga kedua nilai itu diperiksa sebelum isi dipakai. Pola tiga langkah pada program di atas, yaitu menyiapkan folder, menulis, kemudian membaca ulang, juga menjadi cara yang mudah untuk menguji bahwa operasi berkas benar-benar berhasil.
Keduanya sebenarnya pembungkus yang ringkas atas siklus buka-tutup berkas, yaitu membuka berkas, membaca atau menulis seluruh isinya sekali jalan, lalu menutupnya, sehingga cocok untuk berkas berukuran kecil. Untuk tulisan bertahap, os.Create memberi *os.File yang dapat ditulis berkali-kali sebelum ditutup, sedangkan os.Open memberi pembaca yang dibaca sedikit demi sedikit. Perbedaan bentuk keluarannya, yaitu []byte utuh dibandingkan dengan aliran berkas, menjadi pertimbangan utama ketika memilih keduanya.
Aliran data dengan Reader dan Writer#
Tipe os.File memenuhi interface io.Reader dan io.Writer, sehingga berkas dapat dipasang pada fungsi apa pun yang bekerja dengan kontrak aliran data. Fungsi io.Copy adalah contoh komposisinya, yaitu membaca dari satu io.Reader sampai tanda habis data lalu menuliskannya ke satu io.Writer, dan mengembalikan banyaknya byte yang tersalin. Sumbernya tidak harus berkas, karena strings.NewReader, bytes.Buffer, dan koneksi jaringan memenuhi kontrak yang sama. Program berikut menulis teks log ke berkas melalui io.Copy, kemudian membacanya kembali dan mengalirkannya langsung ke os.Stdout yang juga memenuhi io.Writer.
package main
import (
"fmt"
"io"
"os"
"strings"
)
func main() {
jalur := "/tmp/gopustaka/io/log-suhu.txt"
berkas, err := os.Create(jalur)
if err != nil {
fmt.Println("error:", err)
return
}
jumlah, err := io.Copy(berkas, strings.NewReader("log sensor suhu: pagi 24, siang 27, malam 22\n"))
if err != nil {
fmt.Println("error:", err)
return
}
if err := berkas.Close(); err != nil {
fmt.Println("error:", err)
return
}
sumber, err := os.Open(jalur)
if err != nil {
fmt.Println("error:", err)
return
}
defer sumber.Close()
if _, err := io.Copy(os.Stdout, sumber); err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("byte tertulis:", jumlah)
}log sensor suhu: pagi 24, siang 27, malam 22
byte tertulis: 45Program di atas memperlihatkan dua fungsi pembuka berkas yang berbeda tujuan. os.Create membuka berkas untuk ditulis dan mengosongkan isinya, sedangkan os.Open membuka berkas hanya untuk dibaca. Setiap os.File yang selesai dipakai ditutup dengan Close, dan pemanggilan defer menjamin penutupan tetap terjadi meskipun program keluar lebih awal karena error. Baris io.Copy(os.Stdout, sumber) tidak menyebut tipe berkas apa pun, sehingga sumber yang sama dapat ditukar dengan sumber aliran lain tanpa mengubah barisnya.
Komposisi semacam itu dapat disambung beberapa lapis. bytes.Buffer bertindak sebagai penulis di memori yang cocok untuk menampung hasil sementara sebelum dipakai, sedangkan bufio.Writer menyimpan tulisan pada buffer berukuran tetap sebelum diteruskan ke tujuannya. Dengan kontrak yang sama pada setiap lapisnya, sumber dan tujuan dapat ditukar sesuai kebutuhan tanpa menulis ulang fungsi di tengah rantainya. Karena pembacaan dan penulisan berlangsung sepotong-sepotong, memori yang dipakai io.Copy tidak bergantung pada ukuran berkasnya.
Kedua program dapat dijalankan dari terminal sebagaimana berikut, dengan berkas latihan yang ditulis ke folder /tmp agar folder sumber tetap bersih.
# siapkan folder kerja untuk topik ini
mkdir -p /tmp/gopustaka/os-io
cp arsip-berkas.go salin-aliran.go /tmp/gopustaka/os-io/
cd /tmp/gopustaka/os-io
# jalankan program arsip berkas
go run arsip-berkas.go
# jalankan program salin aliran
go run salin-aliran.godibaca 34 byte:
arsip cadangan: 3 berkas tersalin
log sensor suhu: pagi 24, siang 27, malam 22
byte tertulis: 45Kesalahan umum#
- Tidak menutup berkas yang dibuka dengan
os.Createatauos.Open. Berkas yang tidak ditutup menahan sumber daya sistem hingga proses berakhir, dan tulisan yang masih tersisa di buffer dapat hilang. Perbaikannya, tutup berkas dengandefer f.Close()tepat setelah berhasil dibuka. - Menulis ke folder yang belum ada.
os.WriteFiledanos.Createtidak membuat folder otomatis, sehingga keduanya mengembalikan error no such file or directory. Perbaikannya, buat foldernya lebih dahulu denganos.MkdirAll. - Memuat berkas berukuran besar dengan
os.ReadFile. Seluruh isinya ditempatkan di memori, sehingga berkas berukuran gigabyte dapat menghabiskan memori. Perbaikannya, baca berkas secara bertahap denganbufio.Scanneratau salin denganio.Copy. - Menganggap penulisan berkas selalu berhasil. Disk penuh atau izin yang berubah membuat
os.WriteFilemengembalikan error, sedangkan program yang mengabaikannya melanjutkan seolah-olah arsipnya tersimpan. Perbaikannya, periksa error setiap panggilan tulisan sebelum melanjutkan ke langkah berikutnya. - Memakai
os.Createuntuk menambah isi berkas. Fungsi tersebut mengosongkan isi lama, sehingga data sebelumnya hilang. Perbaikannya, buka berkas denganos.OpenFilebeserta benderaos.O_APPENDdanos.O_WRONLY.
Ringkasan#
os.WriteFiledanos.ReadFilemenangani berkas kecil secara utuh, dengan error yang wajib diperiksa pada setiap langkahnya.- Folder penampung harus dibuat lebih dahulu melalui
os.MkdirAll, karena fungsi penulis berkas tidak membuat folder secara otomatis. os.Filememenuhiio.Readerdanio.Writer, sehingga berkas dapat disambungkan ke fungsi aliran data sepertiio.Copy.io.Copymembaca sampai tanda habis data, mengembalikan banyaknya byte, dan bekerja untuk semua pasangan sumber serta tujuan yang memenuhi kontraknya.
Referensi#
- Package os — The Go Authors — Dokumentasi resmi fungsi berkas seperti Create, Open, ReadFile, WriteFile, dan MkdirAll.
- Package io — The Go Authors — Dokumentasi resmi interface Reader dan Writer beserta fungsi Copy.
- The Go Documentation — Halaman induk dokumentasi resmi Go yang memuat panduan pustaka standar.