github.com/karrick/gorill@v1.10.3/filesReader.go (about) 1 package gorill 2 3 import ( 4 "io" 5 "os" 6 ) 7 8 // FilesReader is an io.ReadCloser that can be used to read over the contents of 9 // all of the files specified by pathnames. It only opens a single file handle 10 // at a time. When reading from the currently open file handle returns io.EOF, 11 // it closes that file handle, and the next Read will cause the following file 12 // in the series to be opened and read from. 13 type FilesReader struct { 14 // Pathnames is a list of remaining files to read. It is kept up to date 15 // where when a file is opened, its name is removed from the head of the 16 // list. 17 Pathnames []string 18 19 // fh is the currently open file handle from which Read operations will take 20 // place. It can be nil, in which case Read will attempt to open the next 21 // file in the series and read from it. 22 fh io.ReadCloser 23 } 24 25 // Close forgets the list of remaining files in the series, then closes the 26 // currently open file handle, returning any error from the operating system. 27 func (fr *FilesReader) Close() error { 28 fr.Pathnames = nil 29 if fr.fh == nil { 30 return nil 31 } 32 err := fr.fh.Close() 33 fr.fh = nil 34 return err 35 } 36 37 // Read reads up to len(p) bytes into p. It returns the number of bytes read (0 38 // <= n <= len(p) and any error encountered. 39 func (fr *FilesReader) Read(p []byte) (int, error) { 40 if fr.fh == nil { 41 if err := fr.next(); err != nil { 42 return 0, err 43 } 44 } 45 for { 46 nr, err := fr.fh.Read(p) 47 if err == io.EOF { 48 if err = fr.fh.Close(); err != nil { 49 return nr, err 50 } 51 if err = fr.next(); err != nil { 52 return nr, err 53 } 54 if nr == 0 { 55 continue 56 } 57 } 58 return nr, err 59 } 60 } 61 62 // Next closes the currently open file handle and opens the next file in the 63 // series. If there are no files left it returns io.EOF. It can be used to skip 64 // the remaining contents of the currently open file. Additional Read operations 65 // will be invoked against the following file in the series, if non empty. 66 func (fr *FilesReader) Next() error { 67 if fr.fh != nil { 68 err := fr.fh.Close() 69 fr.fh = nil 70 if err != nil { 71 return err 72 } 73 } 74 return fr.next() 75 } 76 77 // next opens the next file in the series. If there are no files left it returns 78 // io.EOF. 79 func (fr *FilesReader) next() error { 80 if len(fr.Pathnames) == 0 { 81 return io.EOF 82 } 83 84 // The special string "-" reads from standard input, until EOF, but will not 85 // close standard input on EOF. 86 switch fr.Pathnames[0] { 87 case "-": 88 fr.fh = NopCloseReader(os.Stdin) 89 default: 90 fh, err := os.Open(fr.Pathnames[0]) 91 if err != nil { 92 return err 93 } 94 fr.fh = fh 95 } 96 97 fr.Pathnames = fr.Pathnames[1:] 98 return nil 99 }