Skip to content

Instantly share code, notes, and snippets.

@miku

miku/main.go Secret

Last active January 26, 2021 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miku/6e9cdb5225a1814f1758d3b6793ae423 to your computer and use it in GitHub Desktop.
Save miku/6e9cdb5225a1814f1758d3b6793ae423 to your computer and use it in GitHub Desktop.
A reader type that can be checked for EOF without read.
package main
import (
"io"
"io/ioutil"
"log"
"os"
"sync/atomic"
)
// eofReader can be checked for EOF, without a Read. It keeps track of the
// number of bytes read and compares it to the file size, in case the
// underlying type is a file.
type eofReader struct {
r io.Reader
count uint64
}
// AtEOF returns true, if the number of bytes read equals the file size. False
// otherwise.
func (r *eofReader) AtEOF() (bool, error) {
f, ok := r.r.(*os.File)
if !ok {
return false, nil
}
fi, err := f.Stat()
if err != nil {
return false, err
}
return r.Count() == uint64(fi.Size()), nil
}
// Read reads and counts.
func (r *eofReader) Read(buf []byte) (int, error) {
n, err := r.r.Read(buf)
atomic.AddUint64(&r.count, uint64(n))
return n, err
}
// Count returns the count.
func (r *eofReader) Count() uint64 {
return atomic.LoadUint64(&r.count)
}
func main() {
f, err := os.Open("main.go")
if err != nil {
log.Fatal(err)
}
r := &eofReader{r: f}
log.Println(r.AtEOF())
if _, err = ioutil.ReadAll(r); err != nil {
log.Fatal(err)
}
log.Println(r.AtEOF())
}
// 2016/12/19 03:49:35 false <nil>
// 2016/12/19 03:49:35 true <nil>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment