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.

Reply via email to