221 lines
3.7 KiB
Go
221 lines
3.7 KiB
Go
package finder
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"jiacrontab/pkg/file"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
type matchDataChunk struct {
|
|
modifyTime time.Time
|
|
matchData []byte
|
|
}
|
|
|
|
type DataQueue []matchDataChunk
|
|
|
|
func (d DataQueue) Swap(i, j int) {
|
|
d[i], d[j] = d[j], d[i]
|
|
}
|
|
func (d DataQueue) Less(i, j int) bool {
|
|
return d[i].modifyTime.Unix() < d[j].modifyTime.Unix()
|
|
}
|
|
func (d DataQueue) Len() int {
|
|
return len(d)
|
|
}
|
|
|
|
type Finder struct {
|
|
matchDataQueue DataQueue
|
|
curr int32
|
|
regexp *regexp.Regexp
|
|
pagesize int
|
|
errors []error
|
|
patternAll bool
|
|
filter func(os.FileInfo) bool
|
|
isTail bool
|
|
offset int64
|
|
fileSize int64
|
|
}
|
|
|
|
func NewFinder(filter func(os.FileInfo) bool) *Finder {
|
|
return &Finder{
|
|
filter: filter,
|
|
}
|
|
}
|
|
|
|
func (fd *Finder) SetTail(flag bool) {
|
|
fd.isTail = flag
|
|
}
|
|
|
|
func (fd *Finder) Offset() int64 {
|
|
return fd.offset
|
|
}
|
|
|
|
func (fd *Finder) HumanateFileSize() string {
|
|
return file.FileSize(fd.fileSize)
|
|
}
|
|
|
|
func (fd *Finder) FileSize() int64 {
|
|
return fd.fileSize
|
|
}
|
|
|
|
func (fd *Finder) find(fpath string, modifyTime time.Time) error {
|
|
|
|
var matchData []byte
|
|
var reader *bufio.Reader
|
|
|
|
f, err := os.Open(fpath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
info, err := f.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fd.fileSize = info.Size()
|
|
|
|
if fd.fileSize < fd.offset {
|
|
return errors.New("out of file")
|
|
}
|
|
|
|
if fd.isTail {
|
|
if fd.offset < 0 {
|
|
fd.offset = fd.fileSize
|
|
}
|
|
f.Seek(fd.offset, 0)
|
|
reader = bufio.NewReader(NewTailReader(f, fd.offset))
|
|
} else {
|
|
f.Seek(fd.offset, 0)
|
|
reader = bufio.NewReader(f)
|
|
}
|
|
|
|
for {
|
|
|
|
bts, _ := reader.ReadBytes('\n')
|
|
|
|
if len(bts) == 0 {
|
|
break
|
|
}
|
|
|
|
if fd.isTail {
|
|
fd.offset -= int64(len(bts))
|
|
} else {
|
|
fd.offset += int64(len(bts))
|
|
}
|
|
|
|
if fd.isTail {
|
|
if fd.offset == 0 {
|
|
bts = append(bts, '\n')
|
|
}
|
|
invert(bts)
|
|
}
|
|
|
|
if fd.patternAll || fd.regexp.Match(bts) {
|
|
matchData = append(matchData, bts...)
|
|
fd.curr++
|
|
}
|
|
|
|
if fd.curr >= int32(fd.pagesize) {
|
|
break
|
|
}
|
|
|
|
if fd.offset <= 0 {
|
|
break
|
|
}
|
|
|
|
}
|
|
|
|
if len(matchData) > 0 {
|
|
fd.matchDataQueue = append(fd.matchDataQueue, matchDataChunk{
|
|
modifyTime: modifyTime,
|
|
matchData: bytes.TrimLeft(bytes.TrimRight(matchData, "\n"), "\n"),
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (fd *Finder) walkFunc(fpath string, info os.FileInfo, err error) error {
|
|
if !info.IsDir() {
|
|
if fd.filter != nil && fd.filter(info) {
|
|
err := fd.find(fpath, info.ModTime())
|
|
if err != nil {
|
|
fd.errors = append(fd.errors, err)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (fd *Finder) Search(root string, expr string, data *[]byte, offset int64, pagesize int) error {
|
|
var err error
|
|
fd.pagesize = pagesize
|
|
fd.offset = offset
|
|
|
|
if expr == "" {
|
|
fd.patternAll = true
|
|
}
|
|
|
|
if !file.Exist(root) {
|
|
return errors.New(root + " not exist")
|
|
}
|
|
|
|
fd.regexp, err = regexp.Compile(expr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filepath.Walk(root, fd.walkFunc)
|
|
|
|
sort.Stable(fd.matchDataQueue)
|
|
for _, v := range fd.matchDataQueue {
|
|
*data = append(*data, v.matchData...)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (fd *Finder) GetErrors() []error {
|
|
return fd.errors
|
|
}
|
|
|
|
func SearchAndDeleteFileOnDisk(dir string, d time.Duration, size int64) {
|
|
t := time.NewTicker(1 * time.Minute)
|
|
for {
|
|
select {
|
|
case <-t.C:
|
|
filepath.Walk(dir, func(fpath string, info os.FileInfo, err error) error {
|
|
if info == nil {
|
|
return errors.New(fpath + "not exists")
|
|
}
|
|
if !info.IsDir() {
|
|
if time.Now().Sub(info.ModTime()) > d {
|
|
err = os.Remove(fpath)
|
|
|
|
}
|
|
|
|
if info.Size() > size && size != 0 {
|
|
err = os.Remove(fpath)
|
|
|
|
}
|
|
} else {
|
|
// 删除空目录
|
|
err := os.Remove(fpath)
|
|
if err == nil {
|
|
log.Println("delete ", fpath)
|
|
}
|
|
}
|
|
return err
|
|
})
|
|
}
|
|
}
|
|
}
|