github.com/scottcagno/storage@v1.8.0/pkg/_junk/_binary/reader.go (about) 1 package binary 2 3 import ( 4 "encoding/binary" 5 "io" 6 "os" 7 ) 8 9 // Reader provides a read-only file descriptor 10 type Reader struct { 11 path string // path of the file that is currently open 12 fd *os.File // underlying file to read from 13 open bool // is the file open 14 } 15 16 // OpenReader returns a *reader for the file at the provided path 17 func OpenReader(path string) (*Reader, error) { 18 // open file at specified path 19 fd, err := os.OpenFile(path, os.O_RDONLY, 0666) 20 if err != nil { 21 return nil, err 22 } 23 // return new reader 24 return &Reader{ 25 path: path, 26 fd: fd, 27 open: true, 28 }, nil 29 } 30 31 // ReadFrom checks the given path and if it matches, simply returns 32 // the same reader, but if it is different it opens a new one recycling 33 // the same file descriptor. this allows you to read from multiple files 34 // fairly quickly and pain free. 35 func (r *Reader) ReadFrom(path string) (*Reader, error) { 36 // if there is already a file opened 37 if r.open { 38 // and if that file has the same path, simply return r 39 if r.path == path { 40 return r, nil 41 } 42 // otherwise, a file is still opened at a different 43 // location, so we must close it before we continue 44 err := r.Close() 45 if err != nil { 46 return nil, err 47 } 48 } 49 // open a file at a new path (if we're here then the file is closed) 50 fd, err := os.OpenFile(path, os.O_RDONLY, 0666) 51 if err != nil { 52 return nil, err 53 } 54 r.path = path 55 r.fd = fd 56 r.open = true 57 return r, nil 58 } 59 60 func DecodeEntry(r io.Reader) (*Entry, error) { 61 // make buffer 62 buf := make([]byte, 26) 63 // read entry id 64 _, err := r.Read(buf[0:10]) 65 if err != nil { 66 return nil, err 67 } 68 // read entry key length 69 _, err = r.Read(buf[10:18]) 70 if err != nil { 71 return nil, err 72 } 73 // read entry value length 74 _, err = r.Read(buf[18:26]) 75 if err != nil { 76 return nil, err 77 } 78 // decode id 79 id, _ := binary.Varint(buf[0:10]) 80 // decode key length 81 klen := binary.LittleEndian.Uint64(buf[10:18]) 82 // decode value length 83 vlen := binary.LittleEndian.Uint64(buf[18:26]) 84 // make entry to read data into 85 e := &Entry{ 86 Id: id, 87 Key: make([]byte, klen), 88 Value: make([]byte, vlen), 89 } 90 // read key from data into entry key 91 _, err = r.Read(e.Key) 92 if err != nil { 93 return nil, err 94 } 95 // read value key from data into entry value 96 _, err = r.Read(e.Value) 97 if err != nil { 98 return nil, err 99 } 100 // return entry 101 return e, nil 102 } 103 104 func DecodeEntryAt(r io.ReaderAt, offset int64) (*Entry, error) { 105 // make buffer 106 buf := make([]byte, 26) 107 // read entry id 108 n, err := r.ReadAt(buf[0:10], offset) 109 if err != nil { 110 return nil, err 111 } 112 // update offset 113 offset += int64(n) 114 // read entry key length 115 n, err = r.ReadAt(buf[10:18], offset) 116 if err != nil { 117 return nil, err 118 } 119 // update offset 120 offset += int64(n) 121 // read entry value length 122 n, err = r.ReadAt(buf[18:26], offset) 123 if err != nil { 124 return nil, err 125 } 126 // update offset for reading key data a bit below 127 offset += int64(n) 128 // decode id 129 id, _ := binary.Varint(buf[0:10]) 130 // decode key length 131 klen := binary.LittleEndian.Uint64(buf[10:18]) 132 // decode value length 133 vlen := binary.LittleEndian.Uint64(buf[18:26]) 134 // make entry to read data into 135 e := &Entry{ 136 Id: id, 137 Key: make([]byte, klen), 138 Value: make([]byte, vlen), 139 } 140 // read key from data into entry key 141 n, err = r.ReadAt(e.Key, offset) 142 if err != nil { 143 return nil, err 144 } 145 // update offset 146 offset += int64(n) 147 // read value key from data into entry value 148 n, err = r.ReadAt(e.Value, offset) 149 if err != nil { 150 return nil, err 151 } 152 // update offset 153 offset += int64(n) 154 // return entry 155 return e, nil 156 } 157 158 // ReadEntryIndex reads the next encoded entry index, sequentially 159 func (r *Reader) ReadEntryIndex() (*EntryIndex, error) { 160 // check to make sure file is open 161 if !r.open { 162 return nil, ErrFileClosed 163 } 164 // call decode entry 165 return DecodeEntryIndex(r.fd) 166 } 167 168 // ReadEntryIndexAt reads the encoded entry index at the offset provided 169 func (r *Reader) ReadEntryIndexAt(offset int64) (*EntryIndex, error) { 170 // check to make sure file is open 171 if !r.open { 172 return nil, ErrFileClosed 173 } 174 // call decode entry at 175 return DecodeEntryIndexAt(r.fd, offset) 176 } 177 178 // ReadEntry reads the next encoded entry, sequentially 179 func (r *Reader) ReadEntry() (*Entry, error) { 180 // check to make sure file is open 181 if !r.open { 182 return nil, ErrFileClosed 183 } 184 // call decode entry 185 return DecodeEntry(r.fd) 186 } 187 188 // ReadEntryAt reads the encoded entry at the offset provided 189 func (r *Reader) ReadEntryAt(offset int64) (*Entry, error) { 190 // check to make sure file is open 191 if !r.open { 192 return nil, ErrFileClosed 193 } 194 // call decode entry at 195 return DecodeEntryAt(r.fd, offset) 196 } 197 198 // Offset returns the *Reader's current file pointer offset 199 func (r *Reader) Offset() (int64, error) { 200 // check to make sure file is open 201 if !r.open { 202 return -1, ErrFileClosed 203 } 204 // return current offset 205 return r.fd.Seek(0, io.SeekCurrent) 206 } 207 208 // Seek exposes io.Seeker 209 func (r *Reader) Seek(offset int64, whence int) (int64, error) { 210 // check to make sure file is open 211 if !r.open { 212 return -1, ErrFileClosed 213 } 214 // seek to offset according to whence 215 return r.fd.Seek(offset, whence) 216 } 217 218 // Close simply closes the *Reader 219 func (r *Reader) Close() error { 220 // check to make sure file is not already closed 221 if !r.open { 222 return ErrFileClosed 223 } 224 // close the reader 225 err := r.fd.Close() 226 if err != nil { 227 return err 228 } 229 r.open = false 230 r.path = "" 231 return nil 232 }