Alamat berkas kelihatan sederhana, tetapi sistem operasi tidak sepakat soal pemisah: Linux dan macOS memakai / sedangkan Windows memakai \. Program yang merangkai path dengan penggabungan string mentah akan rusak begitu dipindahkan lintas platform. Package path/filepath menyelesaikan masalah tersebut, sementara package path menangani alamat bergaya slash yang tidak pernah menyentuh disk. Chapter ini membahas keduanya plus WalkDir untuk menelusuri direktori.

Merangkai Path dengan filepath.Join #

Fungsi filepath.Join menerima beberapa segmen lalu menyatukannya dengan pemisah yang benar untuk sistem operasi tempat program berjalan. Konstanta filepath.Separator memperlihatkan pemisah tersebut: / di Linux dan \ di Windows. Hasil Join juga selalu bersih — fungsi tersebut menjalankan Clean secara otomatis.

Fungsi filepath.Clean merapikan path berantakan: segmen . dibuang, segmen .. diselesaikan, dan pemisah ganda dilipat menjadi satu. Path belajar/./go/../go/latihan menjadi belajar/go/latihan — alamat yang sama jauh lebih mudah dibanding dan disimpan.

Memecah Path: Dir, Base, dan Ext #

Tiga fungsi kecil memecah path menjadi bagiannya tanpa menyentuh disk:

FungsiHasil untuk catatan/2026/laporan.txtKegunaan
filepath.Dircatatan/2026direktori pembungkus
filepath.Baselaporan.txtnama berkas paling ujung
filepath.Ext.txtekstensi, termasuk titiknya

Ketiganya murni manipulasi teks, sehingga berkas yang dituju tidak perlu ada. Pola umumnya: Base untuk nama tampilan, Ext untuk memilih handler, dan Dir untuk membuat path baru di folder yang sama.

Path Absolut dengan filepath.Abs #

filepath.Abs("data/log.txt") mengembalikan alamat absolut dengan menggabungkan direktori kerja program saat ini. Program demo mencetak hasilnya secara nyata:

Package path untuk Alamat bergaya Slash #

Package path adalah saudara filepath yang selalu memakai /. Pilihannya bukan kebetulan: URL, kunci konfigurasi bertingkat, dan path di dalam fs.FS (misalnya hasil embed) memakai slash di semua platform.

PackagePemisahDipakai untuk
path/filepathmengikuti sistem operasiberkas fisik di disk
pathselalu /URL, kunci konfigurasi, path fs.FS

Menelusuri Direktori dengan WalkDir #

fs.WalkDir mengunjungi direktori induk, lalu seluruh isinya secara berurutan, dan memanggil fungsi callback untuk setiap entri. Mengembalikan nil dari callback membuat penelusuran lanjut; mengembalikan error membuat penelusuran berhenti. Program demo memakai testing/fstest.MapFS sebagai sistem berkas tiruan di memori: struktur proyek beserta isinya dideklarasikan sebagai map, sehingga penelusurannya deterministik tanpa menyentuh disk. Di program sungguhan, callback yang sama bekerja untuk direktori asli lewat os.DirFS maupun filepath.WalkDir.

Program Utuh #

Berkas filepath-demo.go menggabungkan seluruh materi di atas:

go
package main

import (
	"fmt"
	"io/fs"
	"path"
	"path/filepath"
	"testing/fstest"
)

func main() {
	// Join merangkai path dengan pemisah milik sistem operasi.
	fmt.Println("join     :", filepath.Join("belajar", "go", "latihan"))
	fmt.Printf("separator: %q\n", string(filepath.Separator))

	// Clean merapikan titik dan pemisah yang berlebih.
	fmt.Println("clean    :", filepath.Clean("belajar/./go/../go/latihan"))

	// Dir, Base, dan Ext memecah path menjadi bagian-bagiannya.
	berkas := "catatan/2026/laporan.txt"
	fmt.Println("dir      :", filepath.Dir(berkas))
	fmt.Println("base     :", filepath.Base(berkas))
	fmt.Println("ext      :", filepath.Ext(berkas))

	// Abs menghasilkan path absolut dari direktori kerja saat ini.
	absolut, err := filepath.Abs("data/log.txt")
	if err != nil {
		fmt.Println("abs gagal:", err)
		return
	}
	fmt.Println("abs      :", absolut)

	// Package path selalu memakai slash, cocok untuk alamat bergaya URL.
	fmt.Println("path url :", path.Join("/blog", "golang", "fmt"))

	// WalkDir menelusuri struktur direktori secara berurutan.
	sistem := fstest.MapFS{
		"proyek/main.go":          &fstest.MapFile{},
		"proyek/internal/util.go": &fstest.MapFile{},
		"proyek/internal/teks.go": &fstest.MapFile{},
		"proyek/go.mod":           &fstest.MapFile{},
	}
	kesalahan := fs.WalkDir(sistem, "proyek", func(jalur string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		jenis := "file"
		if d.IsDir() {
			jenis = "dir"
		}
		fmt.Printf("walk %-6s %s\n", jenis, jalur)
		return nil
	})
	if kesalahan != nil {
		fmt.Println("walk gagal:", kesalahan)
	}
}

Jalankan program dari folder chapter:

bash
go run filepath-demo.go

Output yang Dihasilkan:

text
join     : belajar/go/latihan
separator: "/"
clean    : belajar/go/latihan
dir      : catatan/2026
base     : laporan.txt
ext      : .txt
abs      : /home/z/my-project/content/go/standard-library/filepath-dan-path/data/log.txt
path url : /blog/golang/fmt
walk dir    proyek
walk file   proyek/go.mod
walk dir    proyek/internal
walk file   proyek/internal/teks.go
walk file   proyek/internal/util.go
walk file   proyek/main.go

Mari kita telaah baris demi baris program di atas:

  1. Baris 13-14: filepath.Join merangkai tiga segmen menjadi satu path portable, lalu filepath.Separator dicetak untuk memperlihatkan pemisah platform saat ini.
  2. Baris 17: filepath.Clean merapikan segmen . dan .. hingga tersisa path paling ringkas.
  3. Baris 20-23: Dir, Base, dan Ext memecah satu path menjadi tiga bagian tanpa membaca berkas.
  4. Baris 26-31: filepath.Abs mengubah path relatif menjadi absolut berdasarkan direktori kerja; error yang mungkin terjadi tetap diperiksa.
  5. Baris 34: path.Join merangkai segmen bergaya URL yang selalu memakai slash.
  6. Baris 37-42: fstest.MapFS mendeklarasikan struktur direktori proyek sebagai map di memori.
  7. Baris 43-53: callback fs.WalkDir memberi label dir atau file pada setiap entri; entri anak diurutkan secara alfabetis sehingga urutan cetak stabil.
  8. Baris 54-56: error penelusuran diperiksa setelah WalkDir selesai — pola yang sama dengan Scanner.Err() pada chapter bufio.

Referensi #

Path kini tersusun rapi lintas platform. Chapter berikutnya menghadapi dimensi lain yang setiap program sadari: waktu — dari memformat tanggal sampai menjadwalkan pekerjaan dengan Timer dan Ticker di package time.

Berkas Sumber

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

filepath-demo.go

Unduh berkas
go
package main

import (
	"fmt"
	"io/fs"
	"path"
	"path/filepath"
	"testing/fstest"
)

func main() {
	// Join merangkai path dengan pemisah milik sistem operasi.
	fmt.Println("join     :", filepath.Join("belajar", "go", "latihan"))
	fmt.Printf("separator: %q\n", string(filepath.Separator))

	// Clean merapikan titik dan pemisah yang berlebih.
	fmt.Println("clean    :", filepath.Clean("belajar/./go/../go/latihan"))

	// Dir, Base, dan Ext memecah path menjadi bagian-bagiannya.
	berkas := "catatan/2026/laporan.txt"
	fmt.Println("dir      :", filepath.Dir(berkas))
	fmt.Println("base     :", filepath.Base(berkas))
	fmt.Println("ext      :", filepath.Ext(berkas))

	// Abs menghasilkan path absolut dari direktori kerja saat ini.
	absolut, err := filepath.Abs("data/log.txt")
	if err != nil {
		fmt.Println("abs gagal:", err)
		return
	}
	fmt.Println("abs      :", absolut)

	// Package path selalu memakai slash, cocok untuk alamat bergaya URL.
	fmt.Println("path url :", path.Join("/blog", "golang", "fmt"))

	// WalkDir menelusuri struktur direktori secara berurutan.
	sistem := fstest.MapFS{
		"proyek/main.go":          &fstest.MapFile{},
		"proyek/internal/util.go": &fstest.MapFile{},
		"proyek/internal/teks.go": &fstest.MapFile{},
		"proyek/go.mod":           &fstest.MapFile{},
	}
	kesalahan := fs.WalkDir(sistem, "proyek", func(jalur string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		jenis := "file"
		if d.IsDir() {
			jenis = "dir"
		}
		fmt.Printf("walk %-6s %s\n", jenis, jalur)
		return nil
	})
	if kesalahan != nil {
		fmt.Println("walk gagal:", kesalahan)
	}
}