Dear all,
I am trying to get the size of an io.ReaderAt, i.e. the offset after which
no more data can be read. I have some working (?) code
(https://go.dev/play/p/wTouYbaJ7RG , also reproduced below), but I am not
sure whether what I do is correct and the best way to do this. Some
questions:
- Does the standard library provide a way to get the size of an
io,ReaderAt?
- Is my code correct?
- Is there a better way to do this?
- If a type provides not only a ReadAt() method, but also a Size()
method, would it be save to assume that Size() returns how many bytes are
accessible via ReadAt()? This seems to work for bytes.Reader and
strings.Reader, but there may be types out there where Size() does
something different?
- If ReadAt(p, x) returns io.EOF for an offset x, is it then guaranteed
that then ReadAt(p, y) also returns io.EOF for all y > x? Or could
there be different error messages, or "files with holes", or whatnot?
- Which types in the standard library provide ReadAt methods? I know of
os.File, strings.Reader, and bytes.Reader. Any others?
For context: this is for reading the cross reference table of PDF files,
which have to be located by following some convoluted route starting *from
the end* of the PDF file.
Many thanks,
Jochen
func getSize(r io.ReaderAt) (int64, error) {
if f, ok := r.(*os.File); ok {
fi, err := f.Stat()
if err != nil {
return 0, err
}
return fi.Size(), nil
}
if b, ok := r.(*bytes.Reader); ok {
return int64(b.Size()), nil
}
if s, ok := r.(*strings.Reader); ok {
return int64(s.Size()), nil
}
buf := make([]byte, 1024)
n, err := r.ReadAt(buf, 0)
if err == io.EOF {
return int64(n), nil
} else if err != nil {
return 0, err
}
lowerBound := int64(n) // all bytes before lowerBound are known to be
present
var upperBound int64 // at least one byte before upperBound is known to
be missing
for {
test := 2 * lowerBound
_, err := r.ReadAt(buf[:1], test-1)
if err == io.EOF {
upperBound = test
break
} else if err != nil {
return 0, err
}
lowerBound = test
}
for lowerBound+1 < upperBound {
test := (lowerBound + upperBound + 1) / 2
_, err := r.ReadAt(buf[:1], test-1)
if err == io.EOF {
upperBound = test
} else if err != nil {
return 0, err
} else {
lowerBound = test
}
}
return lowerBound, nil
}
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/aa604ac0-3542-4a9e-adef-a9eaecfd8170n%40googlegroups.com.