github.com/mondo192/jfrog-client-go@v1.0.0/utils/io/multifilereader.go (about)

     1  package io
     2  
     3  import (
     4  	"github.com/mondo192/jfrog-client-go/utils/errorutils"
     5  	"io"
     6  	"os"
     7  	"sort"
     8  )
     9  
    10  // Create new multi file ReaderAt
    11  func NewMultiFileReaderAt(filePaths []string) (readerAt *multiFileReaderAt, err error) {
    12  	readerAt = &multiFileReaderAt{}
    13  	for _, v := range filePaths {
    14  		f, curErr := os.Open(v)
    15  		if curErr != nil {
    16  			return nil, curErr
    17  		}
    18  		defer func() {
    19  			e := f.Close()
    20  			if err == nil {
    21  				err = errorutils.CheckError(e)
    22  			}
    23  		}()
    24  		stat, curErr := f.Stat()
    25  		if curErr != nil {
    26  			return nil, curErr
    27  		}
    28  
    29  		readerAt.filesPaths = append(readerAt.filesPaths, v)
    30  		readerAt.sizeIndex = append(readerAt.sizeIndex, readerAt.size)
    31  		readerAt.size += stat.Size()
    32  	}
    33  
    34  	return readerAt, nil
    35  }
    36  
    37  type multiFileReaderAt struct {
    38  	filesPaths []string
    39  	size       int64
    40  	sizeIndex  []int64
    41  }
    42  
    43  // Get overall size of all the files.
    44  func (multiFileReader *multiFileReaderAt) Size() int64 {
    45  	return multiFileReader.size
    46  }
    47  
    48  // ReadAt implementation for multi files
    49  func (multiFileReader *multiFileReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
    50  	// Search for the correct index to find the correct file offset
    51  	i := sort.Search(len(multiFileReader.sizeIndex), func(i int) bool { return multiFileReader.sizeIndex[i] > off }) - 1
    52  
    53  	readBytes := 0
    54  	for {
    55  		var f *os.File
    56  		f, err = os.Open(multiFileReader.filesPaths[i])
    57  		if err != nil {
    58  			return
    59  		}
    60  		defer func() {
    61  			e := f.Close()
    62  			if err == nil {
    63  				err = errorutils.CheckError(e)
    64  			}
    65  		}()
    66  		relativeOff := off + int64(n) - multiFileReader.sizeIndex[i]
    67  		readBytes, err = f.ReadAt(p[n:], relativeOff)
    68  		n += readBytes
    69  		if len(p) == n {
    70  			// Finished reading enough bytes
    71  			return
    72  		}
    73  		if err != nil && err != io.EOF {
    74  			// Error
    75  			return
    76  		}
    77  		if i+1 == len(multiFileReader.filesPaths) {
    78  			// No more files to read from
    79  			return
    80  		}
    81  		// Read from the next file
    82  		i++
    83  	}
    84  	// not suppose to get here
    85  }