package file import ( "bufio" "bytes" "io" "os" "path/filepath" "linkfog.com/public/lib/fadvise" "linkfog.com/public/lib/l" "linkfog.com/public/option" ) func FadviseSwitch(f *os.File) { if err := fadvise.Switch(f); err != nil { l.Error(err) } } func PurgeSwitch(path string) { if !option.Fadvise { return } if err := purge(path); err != nil { l.Error(err) } } func purge(path string) error { f, err := os.Open(path) if err != nil { return err } defer f.Close() err = fadvise.Switch(f) if err != nil { return err } return nil } func ReadFileFadvise(name string) ([]byte, error) { f, err := os.Open(name) if err != nil { return nil, err } defer f.Close() defer FadviseSwitch(f) var size int if info, err := f.Stat(); err == nil { size64 := info.Size() if int64(int(size64)) == size64 { size = int(size64) } } size++ // one byte for final read at EOF // If a file claims a small size, read at least 512 bytes. // In particular, files in Linux's /proc claim size 0 but // then do not work right if read in small pieces, // so an initial read of 1 byte would not work correctly. if size < 512 { size = 512 } data := make([]byte, 0, size) for { if len(data) >= cap(data) { d := append(data[:cap(data)], 0) data = d[:len(data)] } n, err := f.Read(data[len(data):cap(data)]) data = data[:len(data)+n] if err != nil { if err == io.EOF { err = nil } return data, err } } } // ReadFileIntoBuffer reads an arbitrary file into a buffer. func ReadFileIntoBufferFadvise(filename string, buf *bytes.Buffer) (int64, error) { f, err := os.Open(filename) if err != nil { return -1, err } defer f.Close() defer FadviseSwitch(f) return buf.ReadFrom(f) } func ReadFileLineFadvise(filePath string) (line string, err error) { if !exist(filePath) { return line, l.WrapError("file not exist.") } fi, err := os.Open(filePath) if err != nil { return line, l.WrapError("open file err:", err, "filePath:", filePath) } defer fi.Close() defer FadviseSwitch(fi) br := bufio.NewReader(fi) for { a, _, c := br.ReadLine() if c == io.EOF { break } return string(a), err } return line, err } func exist(filename string) bool { _, err := os.Stat(filename) return err == nil || !os.IsNotExist(err) } // walk folder to purge file page cache func WalkPurgeSwitch(path string) { if !option.Fadvise { return } if err := walkPurge(path); err != nil { l.Error(err) } } func walkPurge(path string) error { return filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if err != nil { l.Error(err) return nil } if !info.Mode().IsRegular() { return nil } err = purge(path) if err != nil { l.Error(err) } return nil }) }