Skip to content

Instantly share code, notes, and snippets.

@kevsersrca
Created April 13, 2018 08:11
Show Gist options
  • Save kevsersrca/8f5f40f8de58379f9cb03db184d69be7 to your computer and use it in GitHub Desktop.
Save kevsersrca/8f5f40f8de58379f9cb03db184d69be7 to your computer and use it in GitHub Desktop.
remove lines between start and n
package main
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
)
func main() {
if err := removeLines("foobar.txt", 1, 2); err != nil {
fmt.Println(err)
}
}
func removeLines(fn string, start, n int) (err error) {
if start < 1 {
return errors.New("invalid request. line numbers start at 1.")
}
if n < 0 {
return errors.New("invalid request. negative number to remove.")
}
var f *os.File
if f, err = os.OpenFile(fn, os.O_RDWR, 0); err != nil {
return
}
defer func() {
if cErr := f.Close(); err == nil {
err = cErr
}
}()
var b []byte
if b, err = ioutil.ReadAll(f); err != nil {
return
}
cut, ok := skip(b, start-1)
if !ok {
return fmt.Errorf("less than %d lines", start)
}
if n == 0 {
return nil
}
tail, ok := skip(cut, n)
if !ok {
return fmt.Errorf("less than %d lines after line %d", n, start)
}
t := int64(len(b) - len(cut))
if err = f.Truncate(t); err != nil {
return
}
if len(tail) > 0 {
_, err = f.WriteAt(tail, t)
}
return
}
func skip(b []byte, n int) ([]byte, bool) {
for ; n > 0; n-- {
if len(b) == 0 {
return nil, false
}
x := bytes.IndexByte(b, '\n')
if x < 0 {
x = len(b)
} else {
x++
}
b = b[x:]
}
return b, true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment