This page is about golang file seek, golang seek file, go file seek, and plain golang seek: moving the I/O offset on an open file with (*os.File).Seek. Search phrases like seek file or seek go map to the same API. For opening paths and general file work, see how to work with files and read/update patterns. Unrelated queries (for example comma-ok idiom) are not covered here.
Examples use a temporary file on Linux with a recent Go toolchain. Check errors in production code; snippets keep error handling short for clarity.
Golang file seek: (*os.File).Seek and whence
Seek sets the offset for the next Read or Write on the file. The whence argument is usually one of:
io.SeekStart(0): offset is relative to the beginning of the file.io.SeekCurrent(1): offset is added to the current position.io.SeekEnd(2): offset is relative to the end (often negative to read a suffix).
The method returns the new absolute offset and an error. Seek on directories and on files opened with O_APPEND has platform-specific limits described in the os.File.Seek documentation.
Example: absolute seek then read (io.SeekStart)
This program writes known bytes to a temp file, reads the first word, then seeks to an absolute offset before the next read.
package main
import (
"fmt"
"io"
"os"
)
func main() {
payload := []byte("This is an example file. Hello GoLinuxCloud members!")
f, err := os.CreateTemp("", "seek-demo-*.txt")
if err != nil {
fmt.Println(err)
return
}
name := f.Name()
defer os.Remove(name)
if _, err := f.Write(payload); err != nil {
fmt.Println(err)
return
}
f.Close()
file, err := os.Open(name)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
buf := make([]byte, 4)
n, err := file.Read(buf)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("first read (%d): %q\n", n, string(buf[:n]))
if _, err := file.Seek(11, io.SeekStart); err != nil {
fmt.Println(err)
return
}
buf2 := make([]byte, 9)
n2, err := file.Read(buf2)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("after SeekStart(11) read (%d): %q\n", n2, string(buf2[:n2]))
}Run prints a four-byte prefix read, then nine bytes starting at offset 11 ("example f" in the sample payload).
Example: io.SeekCurrent, io.SeekEnd, and tail reads
package main
import (
"fmt"
"io"
"os"
)
func main() {
payload := []byte("This is an example file. Hello GoLinuxCloud members!")
f, err := os.CreateTemp("", "seek-demo2-*.txt")
if err != nil {
fmt.Println(err)
return
}
name := f.Name()
defer os.Remove(name)
if _, err := f.Write(payload); err != nil {
fmt.Println(err)
return
}
f.Close()
file, err := os.Open(name)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
buf := make([]byte, 4)
if _, err := file.Read(buf); err != nil {
fmt.Println(err)
return
}
fmt.Printf("first 4 bytes: %q\n", string(buf))
if _, err := file.Seek(4, io.SeekCurrent); err != nil {
fmt.Println(err)
return
}
buf2 := make([]byte, 7)
n2, err := file.Read(buf2)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("after SeekCurrent(+4): %q\n", string(buf2[:n2]))
if _, err := file.Seek(-5, io.SeekEnd); err != nil {
fmt.Println(err)
return
}
buf3 := make([]byte, 5)
n3, err := file.Read(buf3)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("last 5 bytes: %q\n", string(buf3[:n3]))
}Run shows This, then an exam from the relative seek, then the last five bytes of the payload (bers! in the fixed string).
Golang seek without a file: bytes.Reader
For parsers that want the same offset model on memory, bytes.Reader implements Seek:
package main
import (
"bytes"
"fmt"
"io"
)
func main() {
r := bytes.NewReader([]byte("hello"))
if _, err := r.Seek(-2, io.SeekEnd); err != nil {
fmt.Println(err)
return
}
buf := make([]byte, 8)
n, err := r.Read(buf)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%q\n", string(buf[:n]))
}Run prints "lo" from the end of the string.
Summary
Golang file seek and go file seek both come down to (*os.File).Seek with io.SeekStart, io.SeekCurrent, or io.SeekEnd, always paired with error handling and a clear next Read or Write. Golang seek file workflows should respect append mode and directory limitations from the docs. When you only need golang seek semantics on in-memory bytes, bytes.NewReader gives the same Seek model without touching the filesystem.

