filepath.Join în Go

Unește mai multe bucăți într-o cale, cu separatorul corect al sistemului, și curăță rezultatul.

Sintaxă
func Join(elem ...string) string

Ce face filepath.Join

filepath.Join lipește elementele cu separatorul sistemului (/ pe Linux și macOS, \ pe Windows) și apoi aplică filepath.Clean: elimină separatoarele duble, . și rezolvă .. unde se poate. Elementele goale sunt ignorate.

Este modul corect de a construi căi în Go. Lipirea cu + "/" + dă greș pe Windows și lasă separatoare duble când o bucată se termină deja cu /.

Atenție: Join nu verifică dacă rezultatul rămâne în directorul de bază. filepath.Join("uploads", "../../etc/passwd") dă ../etc/passwd. Pentru nume venite de la utilizatori verifică întâi cu filepath.IsLocal.

Parametri

Parametru Descriere
elem Bucățile căii, oricâte.

Ce returnează

Calea rezultată, curățată. Join() fără elemente (sau doar cu elemente goale) returnează "".

Exemple

Exemplul 1: Construirea căilor

Rezultatul este cel de pe Linux/macOS; pe Windows separatorul ar fi \.

package main

import (
    "fmt"
    "path/filepath"
)

func main() {
    fmt.Println(filepath.Join("home", "ana", "poze", "iasi.jpg"))
    fmt.Println(filepath.Join("/var/www/", "/site/", "index.html"))
    fmt.Println(filepath.Join("date", "", "2025", "raport.csv"))
    fmt.Println(filepath.Join("proiect/src", "../docs", "./ghid.md"))
}

Rezultat

home/ana/poze/iasi.jpg
/var/www/site/index.html
date/2025/raport.csv
proiect/docs/ghid.md

Exemplul 2: Fișiere într-un director de lucru

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    baza := "rapoarte"
    for _, luna := range []string{"ianuarie", "februarie"} {
        dir := filepath.Join(baza, "2025", luna)
        os.MkdirAll(dir, 0o755)
        fisier := filepath.Join(dir, "vanzari.csv")
        os.WriteFile(fisier, []byte("produs,suma\n"), 0o644)
        fmt.Println("creat:", fisier)
    }
}

Rezultat

creat: rapoarte/2025/ianuarie/vanzari.csv
creat: rapoarte/2025/februarie/vanzari.csv

Exemplul 3: Join nu te protejează de „..”

package main

import (
    "fmt"
    "path/filepath"
)

func main() {
    for _, nume := range []string{"poza.jpg", "../../etc/passwd", "albume/vara.jpg"} {
        cale := filepath.Join("uploads", nume)
        fmt.Printf("%-20s -> %-18s local: %v\n", nume, cale, filepath.IsLocal(nume))
    }
}

Rezultat

poza.jpg             -> uploads/poza.jpg   local: true
../../etc/passwd     -> ../etc/passwd      local: false
albume/vara.jpg      -> uploads/albume/vara.jpg local: true

Greșeli frecvente

  • Construiești căi cu + "/" +. Pe Windows rezultatul amestecă separatoarele, iar un / în plus dă //.
  • Folosești filepath.Join pentru URL-uri sau pentru căi dintr-un fs.FS. Acolo separatorul trebuie să fie mereu /; folosește path.Join sau url.JoinPath.
  • Lipești direct numele trimise de utilizatori. Verifică cu filepath.IsLocal ca să nu poată ieși din director.

Comenzi înrudite

  • filepath.Clean: Simplifică o cale: elimină separatoarele duble, „.” și rezolvă „..” doar din text, fără acces la disc.
  • filepath.Split: Împarte o cale în director (cu separatorul final) și numele fișierului.
  • filepath.IsLocal: Spune dacă o cale rămâne în interiorul directorului curent: nu e absolută, nu e goală și nu urcă cu „..”.
  • filepath.Dir: Returnează partea de director a unei căi: tot ce este înainte de ultimul element.
  • filepath.Base: Returnează ultimul element al unei căi: numele fișierului (sau al ultimului director).