os.File.Seek în Go

Mută poziția curentă de citire/scriere din fișier, față de început, de poziția curentă sau de final.

Sintaxă
func (f *File) Seek(offset int64, whence int) (ret int64, err error)

Ce face os.File.Seek

Fiecare fișier deschis are o poziție curentă; Read și Write pornesc de acolo. Seek o mută la offset octeți față de un punct de referință: io.SeekStart (începutul), io.SeekCurrent (poziția actuală) sau io.SeekEnd (finalul).

Returnează noua poziție, măsurată de la început. Trucul f.Seek(0, io.SeekCurrent) afli poziția fără s-o schimbi, iar f.Seek(0, io.SeekEnd) returnează dimensiunea fișierului. Pe un fișier deschis cu O_APPEND, scrierea merge oricum la final.

Parametri

Parametru Descriere
offset Câți octeți să se deplaseze; poate fi negativ față de io.SeekCurrent sau io.SeekEnd.
whence Punctul de referință: io.SeekStart, io.SeekCurrent, io.SeekEnd.

Ce returnează

Noua poziție (de la începutul fișierului) și nil, sau o eroare.

Exemple

Exemplul 1: Citire de la o poziție anume

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    os.WriteFile("alfabet.txt", []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0o644)
    f, _ := os.Open("alfabet.txt")
    defer f.Close()

    buf := make([]byte, 3)
    poz, _ := f.Seek(10, io.SeekStart)
    f.Read(buf)
    fmt.Printf("de la %d: %s\n", poz, buf)

    poz, _ = f.Seek(-3, io.SeekEnd)
    f.Read(buf)
    fmt.Printf("de la %d: %s\n", poz, buf)

    dim, _ := f.Seek(0, io.SeekEnd)
    fmt.Println("dimensiune:", dim)
}

Rezultat

de la 10: KLM
de la 23: XYZ
dimensiune: 26

Exemplul 2: Recitirea de la început

După io.ReadAll poziția este la final; fără Seek, a doua citire ar fi goală.

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    os.WriteFile("lista.txt", []byte("mere, pere, prune"), 0o644)
    f, _ := os.Open("lista.txt")
    defer f.Close()

    prima, _ := io.ReadAll(f)
    adoua, _ := io.ReadAll(f)
    fmt.Printf("prima: %q | a doua: %q\n", prima, adoua)

    f.Seek(0, io.SeekStart)
    atreia, _ := io.ReadAll(f)
    fmt.Printf("după Seek: %q\n", atreia)
}

Rezultat

prima: "mere, pere, prune" | a doua: ""
după Seek: "mere, pere, prune"

Exemplul 3: Modificarea unui octet în loc

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    os.WriteFile("cod.txt", []byte("PRODUS-A-2025"), 0o644)
    f, _ := os.OpenFile("cod.txt", os.O_RDWR, 0)
    f.Seek(7, io.SeekStart)
    f.Write([]byte("B"))
    f.Close()

    date, _ := os.ReadFile("cod.txt")
    fmt.Println(string(date))
}

Rezultat

PRODUS-B-2025

Greșeli frecvente

  • Citești de două ori același fișier și a doua oară nu primești nimic. Poziția a rămas la final; apelează Seek(0, io.SeekStart).
  • Folosești Seek pe os.Stdin sau pe un pipe. Acestea nu permit deplasarea și dau eroare.

Comenzi înrudite

  • os.File.Read: Citește din fișier cel mult len(b) octeți în slice-ul b și returnează câți a citit.
  • os.Truncate: Schimbă dimensiunea unui fișier: taie ce depășește sau completează cu octeți zero.
  • os.File: Tipul care reprezintă un fișier deschis; îl obții cu os.Open, os.Create sau os.OpenFile.
  • io.ReadAll: Citește tot ce oferă un Reader, până la final, și returnează datele ca slice de octeți.