Link Search Menu Expand Document

Seeking a position within a file

  • In some cases, you need to read from or write to a particular location in a file, such as an indexed file. The recipe will show you how to use the position seeking in the context of flat file operations.

Create the file flatfile.txt with the following content:

      123.Jun.......Wong......
      12..Novak.....Jurgen....
      10..Thomas....Sohlich...

Create the fileseek.go file with the following content:

package main

import (
	"errors"
	"fmt"
	"os"
)

const lineLegth = 25

func main() {

	f, e := os.OpenFile("flatfile.txt", os.O_RDWR|os.O_CREATE,
		os.ModePerm)
	if e != nil {
		panic(e)
	}
	defer f.Close()

	fmt.Println(readRecords(2, "last", f))
	if err := writeRecord(2, "first", "Radomir", f); err != nil {
		panic(err)
	}
	fmt.Println(readRecords(2, "first", f))
	if err := writeRecord(10, "first", "Andrew", f); err != nil {
		panic(err)
	}
	fmt.Println(readRecords(10, "first", f))
	fmt.Println(readLine(2, f))
}

func readLine(line int, f *os.File) (string, error) {
	lineBuffer := make([]byte, 24)
	f.Seek(int64(line*lineLegth), 0)
	_, err := f.Read(lineBuffer)
	return string(lineBuffer), err
}

func writeRecord(line int, column, dataStr string, f *os.File) error {
	definedLen := 10
	position := int64(line * lineLegth)
	switch column {
	case "id":
		definedLen = 4
	case "first":
		position += 4
	case "last":
		position += 14
	default:
		return errors.New("Column not defined")
	}

	if len([]byte(dataStr)) > definedLen {
		return fmt.Errorf("Maximum length for '%s' is %d",
			column, definedLen)
	}

	data := make([]byte, definedLen)
	for i := range data {
		data[i] = '.'
	}
	copy(data, []byte(dataStr))
	_, err := f.WriteAt(data, position)
	return err
}

func readRecords(line int, column string, f *os.File) (string, error) {
	lineBuffer := make([]byte, 24)
	f.ReadAt(lineBuffer, int64(line*lineLegth))
	var retVal string
	switch column {
	case "id":
		return string(lineBuffer[:3]), nil
	case "first":
		return string(lineBuffer[4:13]), nil
	case "last":
		return string(lineBuffer[14:23]), nil
	}

	return retVal, errors.New("Column not defined")
}



output:

sangam:golang-daily sangam$ go run fileseek.go
Sohlich.. <nil>
Radomir.. <nil>
Andrew... <nil>
10..Radomir...Sohlich... <nil>
sangam:golang-daily sangam$ 

Display the file in hex xxd flatfile.txt.

sangam:golang-daily sangam$ xxd flatfile.txt
00000000: 3132 332e 4a75 6e2e 2e2e 2e2e 2e2e 576f  123.Jun.......Wo
00000010: 6e67 2e2e 2e2e 2e2e 0a31 322e 2e4e 6f76  ng.......12..Nov
00000020: 616b 2e2e 2e2e 2e4a 7572 6765 6e2e 2e2e  ak.....Jurgen...
00000030: 2e0a 3130 2e2e 5261 646f 6d69 722e 2e2e  ..10..Radomir...
00000040: 536f 686c 6963 682e 2e2e 0a00 0000 0000  Sohlich.........
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 416e  ..............An
00000100: 6472 6577 2e2e 2e2e                      drew....
sangam:golang-daily sangam$ 

How it works…

  • The preceding example uses the flatfile as an illustration of how to seek, read and write at the position in the file. In general, for moving the position of the current pointer in the File, the Seek method can be used. It takes two arguments and these are, position and how to count the position, 0 - relative to file origin, 1 - relative to current position, 2 - relative to the end of file. This way you are able to move the cursor within the file.

  • Note : The flatfile is the most basic form of how to store the data. The record structure has a fixed length and the same for the record parts. The structure of the flat file in the example is: ID - 4 chars, FirstName - 10 chars, LastName - 10 chars. The whole record is 24 chars long, ended by a line break which is the 25th character. The Seek method is used in the implementation of the readLine function in the preceding code.

  • The os.File also contains the ReadAt and WriteAt methods. These methods consume that the bytes to be written/read and the offset where to start. These simplify the writing and reading to a certain position in a file.