Dear Bruno, Thanks for your answer. Originally I had a separate size argument for the function which opens a new reader, something like this:
func NewReader(data io.ReaderAt, size int64, opt *ReaderOptions) (*Reader, error) But this makes it a bit annoying to create a reader for a file, because you always need the additional Stat() call before, and also it looks a bit weird, I though. So my idea was to move the code for checking the size into the function, and to simplify the API: func NewReader(data io.ReaderAt, opt *ReaderOptions) (*Reader, error) This way the library does the work once, rather than every caller having to do this separately. All the best, Jochen On Friday, 31 March 2023 at 21:38:04 UTC+1 Bruno Albuquerque wrote: > Not a direct answer to your question (your code looks like a reasonable > implementation modulo any bugs I did not notice) but: Aren't you over > engineering things? If the source is a PDF file, why not also pass the size > to the function instead of doing all this work to get it? At some point you > have to open the file, right? And checking the size of a file is trivial > (it is just a stat call) and then you do not need to do that. > > > On Fri, Mar 31, 2023 at 4:30 PM Jochen Voss <joche...@gmail.com> wrote: > >> 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 golang-nuts...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/aa604ac0-3542-4a9e-adef-a9eaecfd8170n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/aa604ac0-3542-4a9e-adef-a9eaecfd8170n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- 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 golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1be784af-63e5-4238-bd96-ef3123318d68n%40googlegroups.com.