github.com/wangyougui/gf/v2@v2.6.5/os/gfile/gfile_contents.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gfile 8 9 import ( 10 "bufio" 11 "io" 12 "os" 13 14 "github.com/wangyougui/gf/v2/errors/gerror" 15 ) 16 17 var ( 18 // DefaultReadBuffer is the buffer size for reading file content. 19 DefaultReadBuffer = 1024 20 ) 21 22 // GetContents returns the file content of `path` as string. 23 // It returns en empty string if it fails reading. 24 func GetContents(path string) string { 25 return string(GetBytes(path)) 26 } 27 28 // GetBytes returns the file content of `path` as []byte. 29 // It returns nil if it fails reading. 30 func GetBytes(path string) []byte { 31 data, err := os.ReadFile(path) 32 if err != nil { 33 return nil 34 } 35 return data 36 } 37 38 // putContents puts binary content to file of `path`. 39 func putContents(path string, data []byte, flag int, perm os.FileMode) error { 40 // It supports creating file of `path` recursively. 41 dir := Dir(path) 42 if !Exists(dir) { 43 if err := Mkdir(dir); err != nil { 44 return err 45 } 46 } 47 // Opening file with given `flag` and `perm`. 48 f, err := OpenWithFlagPerm(path, flag, perm) 49 if err != nil { 50 return err 51 } 52 defer f.Close() 53 // Write data. 54 var n int 55 if n, err = f.Write(data); err != nil { 56 err = gerror.Wrapf(err, `Write data to file "%s" failed`, path) 57 return err 58 } else if n < len(data) { 59 return io.ErrShortWrite 60 } 61 return nil 62 } 63 64 // Truncate truncates file of `path` to given size by `size`. 65 func Truncate(path string, size int) (err error) { 66 err = os.Truncate(path, int64(size)) 67 if err != nil { 68 err = gerror.Wrapf(err, `os.Truncate failed for file "%s", size "%d"`, path, size) 69 } 70 return 71 } 72 73 // PutContents puts string `content` to file of `path`. 74 // It creates file of `path` recursively if it does not exist. 75 func PutContents(path string, content string) error { 76 return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen) 77 } 78 79 // PutContentsAppend appends string `content` to file of `path`. 80 // It creates file of `path` recursively if it does not exist. 81 func PutContentsAppend(path string, content string) error { 82 return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen) 83 } 84 85 // PutBytes puts binary `content` to file of `path`. 86 // It creates file of `path` recursively if it does not exist. 87 func PutBytes(path string, content []byte) error { 88 return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen) 89 } 90 91 // PutBytesAppend appends binary `content` to file of `path`. 92 // It creates file of `path` recursively if it does not exist. 93 func PutBytesAppend(path string, content []byte) error { 94 return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen) 95 } 96 97 // GetNextCharOffset returns the file offset for given `char` starting from `start`. 98 func GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 { 99 buffer := make([]byte, DefaultReadBuffer) 100 offset := start 101 for { 102 if n, err := reader.ReadAt(buffer, offset); n > 0 { 103 for i := 0; i < n; i++ { 104 if buffer[i] == char { 105 return int64(i) + offset 106 } 107 } 108 offset += int64(n) 109 } else if err != nil { 110 break 111 } 112 } 113 return -1 114 } 115 116 // GetNextCharOffsetByPath returns the file offset for given `char` starting from `start`. 117 // It opens file of `path` for reading with os.O_RDONLY flag and default perm. 118 func GetNextCharOffsetByPath(path string, char byte, start int64) int64 { 119 if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil { 120 defer f.Close() 121 return GetNextCharOffset(f, char, start) 122 } 123 return -1 124 } 125 126 // GetBytesTilChar returns the contents of the file as []byte 127 // until the next specified byte `char` position. 128 // 129 // Note: Returned value contains the character of the last position. 130 func GetBytesTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) { 131 if offset := GetNextCharOffset(reader, char, start); offset != -1 { 132 return GetBytesByTwoOffsets(reader, start, offset+1), offset 133 } 134 return nil, -1 135 } 136 137 // GetBytesTilCharByPath returns the contents of the file given by `path` as []byte 138 // until the next specified byte `char` position. 139 // It opens file of `path` for reading with os.O_RDONLY flag and default perm. 140 // 141 // Note: Returned value contains the character of the last position. 142 func GetBytesTilCharByPath(path string, char byte, start int64) ([]byte, int64) { 143 if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil { 144 defer f.Close() 145 return GetBytesTilChar(f, char, start) 146 } 147 return nil, -1 148 } 149 150 // GetBytesByTwoOffsets returns the binary content as []byte from `start` to `end`. 151 // Note: Returned value does not contain the character of the last position, which means 152 // it returns content range as [start, end). 153 func GetBytesByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte { 154 buffer := make([]byte, end-start) 155 if _, err := reader.ReadAt(buffer, start); err != nil { 156 return nil 157 } 158 return buffer 159 } 160 161 // GetBytesByTwoOffsetsByPath returns the binary content as []byte from `start` to `end`. 162 // Note: Returned value does not contain the character of the last position, which means 163 // it returns content range as [start, end). 164 // It opens file of `path` for reading with os.O_RDONLY flag and default perm. 165 func GetBytesByTwoOffsetsByPath(path string, start int64, end int64) []byte { 166 if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil { 167 defer f.Close() 168 return GetBytesByTwoOffsets(f, start, end) 169 } 170 return nil 171 } 172 173 // ReadLines reads file content line by line, which is passed to the callback function `callback` as string. 174 // It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker. 175 // 176 // Note that the parameter passed to callback function might be an empty value, and the last non-empty line 177 // will be passed to callback function `callback` even if it has no newline marker. 178 func ReadLines(file string, callback func(line string) error) error { 179 f, err := Open(file) 180 if err != nil { 181 return err 182 } 183 defer f.Close() 184 185 scanner := bufio.NewScanner(f) 186 for scanner.Scan() { 187 if err = callback(scanner.Text()); err != nil { 188 return err 189 } 190 } 191 return nil 192 } 193 194 // ReadLinesBytes reads file content line by line, which is passed to the callback function `callback` as []byte. 195 // It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker. 196 // 197 // Note that the parameter passed to callback function might be an empty value, and the last non-empty line 198 // will be passed to callback function `callback` even if it has no newline marker. 199 func ReadLinesBytes(file string, callback func(bytes []byte) error) error { 200 f, err := Open(file) 201 if err != nil { 202 return err 203 } 204 defer f.Close() 205 206 scanner := bufio.NewScanner(f) 207 for scanner.Scan() { 208 if err = callback(scanner.Bytes()); err != nil { 209 return err 210 } 211 } 212 return nil 213 }