Or the caller can wrap the object with io.NewSectionReader 
<https://pkg.go.dev/io#NewSectionReader>(f, 0, len)

On Saturday, 1 April 2023 at 10:51:11 UTC+1 Brian Candler wrote:

> Could you make your function accept some other interface? e.g.
>
> type SizeReaderAt interface {
>     io.ReaderAt
>     Size() int64 
> }
>
> Values of this type will still be able to satisfy io.ReaderAt at point of 
> use.
>
> You could also use the existing io.SectionReader 
> <https://pkg.go.dev/io#SectionReader> which has has Read(), ReadAt(), 
> Seek() and Size() methods.
>
> Another option is to define your own interface:
>  
> type StatReaderAt interface {
>     io.ReaderAt
>     Stat() (os.FileInfo, error) 
> }
>
> This interface also already satisfied if the caller is passing a concrete 
> *os.File. However if they aren't, then the caller has a bit of work to wrap 
> their value so that it carries a Stat() method which returns a value that 
> satisfies FileInfo <https://pkg.go.dev/io/fs#FileInfo> (with 6 methods, 
> although 5 of those could be dummies).
>
> It's unfortunate that *os.File doesn't automatically satisfy 
> io.SectionReader (since File doesn't have a Size() method). But I guess you 
> could make a type which embeds *os.File and adds a Size() method which 
> calls Stat().Size().
>
> On Saturday, 1 April 2023 at 09:58:28 UTC+1 Jochen Voss wrote:
>
>> 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/a85a20e3-d87d-4df6-a257-92c8a99afbeen%40googlegroups.com.

Reply via email to