Skip to content

Instantly share code, notes, and snippets.

@alessiosavi
Last active November 7, 2019 10:13
Show Gist options
  • Save alessiosavi/d1f35e4db31109ffa961d847eb5d9af6 to your computer and use it in GitHub Desktop.
Save alessiosavi/d1f35e4db31109ffa961d847eb5d9af6 to your computer and use it in GitHub Desktop.
Tail a file in Golang
package main
import (
"log"
"os"
"strings"
)
// JoinStrings use a strings.Builder for concatenate the input string array.
// It concatenate the strings among the delimiter in input
func JoinStrings(strs []string, delimiter string) string {
if len(strs) == 0 {
return ""
}
var sb strings.Builder
for i := range strs {
sb.WriteString(strs[i])
sb.WriteString(delimiter)
}
return strings.TrimSuffix(sb.String(), delimiter)
}
const FILE string = `test.txt`
// BUFF_BYTE is how many bytes to move
// BUFF_BYTE can be positive or negative
const BUFF_BYTE int64 = -1
// Whence is the point of reference for offset
// 0 = Beginning of file
// 1 = Current position
// 2 = End of file
const START_POS int = 2
const N_STRING = 100
func Tail(FILE string, BUFF_BYTE int64, START_POS, N_STRING int) string {
// list of strings readed
var stringsArray []string = make([]string, N_STRING)
// Contains the data
var buff []byte = make([]byte, -BUFF_BYTE)
if !(START_POS >= 0 && START_POS <= 2) {
log.Fatal("Wrong argument for Seek ...")
}
file, err := os.Open(FILE)
if err != nil {
log.Println("Unable to open file: " + FILE + " ERR: " + err.Error())
log.Fatal(err)
}
defer file.Close()
// Go to end of file
_, err = file.Seek(BUFF_BYTE, START_POS)
if err != nil {
log.Println("Unable to seek to the end of the file: " + FILE + " ERR: " + err.Error())
log.Fatal(err)
}
var linesReaded int = 0
var nByte int // Number of byte readed
var stringBuffer string = "" // Contains the string until we don't found the new line
var iteration int64 = 1
var n int64 = -BUFF_BYTE // Just for pass the first check
var lastPosition int64
// Until we haven't read all the string
for linesReaded < N_STRING {
if n >= -BUFF_BYTE {
n, err = file.Seek(iteration*BUFF_BYTE, START_POS)
if err != nil {
log.Println("2) Error during read of file | Lines readed: ", linesReaded, " Byte readed: ", nByte, " Iteration: ", iteration)
log.Fatal(err)
}
lastPosition = n
} else {
// We have not enought data for fill the buffer, seeking to the start of the file
file.Seek(0, 0)
buff = make([]byte, lastPosition)
_, err = file.Read(buff)
if err != nil {
log.Println("3) Error during read of file | Lines readed: ", linesReaded, " Byte readed: ", nByte, " Iteration: ", iteration)
log.Fatal(err)
}
stringBuffer = string(buff) + stringBuffer
stringsArray[N_STRING-linesReaded-1] = stringBuffer
break
}
// Read the string related to the buffer
nByte, err = file.Read(buff)
if err != nil {
log.Println("1) Error during read of file | Lines readed: ", linesReaded, " Byte readed: ", nByte, " Iteration: ", iteration)
log.Fatal(err)
}
// Append the string in initial position
stringBuffer = string(buff) + stringBuffer
if strings.Contains(stringBuffer, "\n") {
stringsArray[N_STRING-linesReaded-1] = stringBuffer
stringBuffer = ""
linesReaded++
// Continue to read, we have not found a new line and we have enough file to read
}
iteration++
}
stringsArray = stringsArray[linesReaded-1:]
return JoinStrings(stringsArray, "")
}
func main() {
log.Println(Tail(FILE, BUFF_BYTE, START_POS, N_STRING))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment