Go os.ReadDir 在运行时读取已删除的文件

huangapple go评论69阅读模式
英文:

Go os.ReadDir reading files deleted in run time

问题

我有一个程序,可以在同一个目录下的文件系统中找到最大的文件。如果我调用FileDisplay.Delete函数,然后重新运行GetTopXFiles函数来获取目录中的文件,它会返回已经被删除的文件。在程序仍在运行时,我可以使用ls命令看到文件已经不存在了。有趣的是,如果我使用fallocate -l 251.2M file100命令创建一个新文件,我可以看到这个新创建的文件被认为是最大的文件。然后,如果我使用rm命令或程序将其删除,重新运行GetTopXFiles函数,它仍然会返回该文件。如果我重新启动程序,它会识别到该文件已经不存在。

以上是一个用Go语言编写的程序,用于查找文件并显示文件大小和路径。它包括以下函数:

  • GetTopXFiles函数用于获取指定目录下最大的文件列表。
  • Delete函数用于删除指定文件。
  • Append函数用于向文件列表中添加文件。

请问有什么我可以帮助你的吗?

英文:

I have a program that is finding the larges files on a filesystem within the same directory. If I call FileDisplay.Delete function and then re-run GetTopXFiles on the directory, it returns files that had been deleted. Using ls while the program is still running, I can see that the files is no longer there. Interestingly, if I fallocate -l 251.2M file100 I can see my newly created file as being the largest file. If I then remove it using rm or the program, re-run the GetTopXFiles it still returns. If I restart the program it recognizes the file is gone.

package fileFinder

import (
	"fmt"
	"io"
	"io/fs"
	"log"
	"os"
	"sort"
	"sync"

	"github.com/google/fscrypt/filesystem"
	"github.com/sirupsen/logrus"
)

var device string

type fileDisplay struct {
	sync.RWMutex
	Files []FileDisplay
}

var files fileDisplay

type FileDisplay struct {
	Size int64  `json:"size"`
	Path string `json:"path"`
}
type bySize []FileDisplay

func (a bySize) Len() int           { return len(a) }
func (a bySize) Less(i, j int) bool { return a[i].Size < a[j].Size }
func (a bySize) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func GetTopXFiles(mountpoint string, limit int) ([]FileDisplay, error) {
	log.SetOutput(io.Discard)
	if mountpoint == "" {
		return nil, fmt.Errorf("Path cannot be empty")
	}
	if limit < 1 {
		return nil, fmt.Errorf("Limit must be 1 or greater")

	}
	if mountpoint[len(mountpoint)-1:] != "/" {
		mountpoint = mountpoint + "/"
	}
	mount, err := filesystem.FindMount(mountpoint)
	if err != nil {
		return nil, err
	}
	device = mount.Device

	entries, err := os.ReadDir(mountpoint)
	if err != nil {
		return nil, err
	}
	var wg sync.WaitGroup
	getFiles(mountpoint, entries, &wg)
	wg.Wait()
	sort.Sort(bySize(files.Files))
	var shortFiles []FileDisplay
	if len(files.Files) > limit {
		shortFiles = files.Files[len(files.Files)-limit:]
	} else {
		shortFiles = files.Files
	}

	return shortFiles, nil

}

func getFiles(start string, entries []fs.DirEntry, wg *sync.WaitGroup) {
	for _, entry := range entries {
		wg.Add(1)
		go handleEntry(start, entry, wg)
	}

}

func handleEntry(start string, entry fs.DirEntry, wg *sync.WaitGroup) {
	defer wg.Done()
	var file FileDisplay
	mount, err := filesystem.FindMount(start + entry.Name())
	if err != nil {
		logrus.Errorln(err, start+entry.Name())
		return
	}
	if mount.Device == device {
		if entry.Type().IsRegular() {
			fileInfo, err := os.Stat(start + entry.Name())
			if err != nil {
				logrus.Errorln(err, start+entry.Name())
				return
			}
			file.Path = start + entry.Name()
			file.Size = fileInfo.Size()
			files.Append(file)
		} else if entry.IsDir() {
			entries, err := os.ReadDir(start + entry.Name())
			if err != nil {
				logrus.Errorln(err, start+entry.Name())
				return
			}
			logrus.Info("Searching ", start+entry.Name())
			getFiles(start+entry.Name()+"/", entries, wg)
		}
	}

}

func (f *FileDisplay) DisplaySizeIEC() string {
	const unit = 1024
	b := f.Size
	if b < unit {
		return fmt.Sprintf("%dB", b)
	}
	div, exp := int64(unit), 0
	for n := b / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.2f%ciB",
		float64(b)/float64(div), "KMGTPE"[exp])
}

func (f *FileDisplay) Delete() error {
	err := os.Remove(f.Path)
	if err != nil {
		return err
	}
	return nil
}

func (fd *fileDisplay) Append(item FileDisplay) {
	fd.Lock()
	defer fd.Unlock()

	fd.Files = append(fd.Files, item)
}

答案1

得分: 1

var files fileDisplay

files是一个全局的fileDisplay变量,其中包含一个由GetTopXFiles填充的[]FileDisplay。但是,即使调用了Delete,也没有更新files。因此,在删除后,files中包含的是已被删除的文件。

最简单的解决方案是不使用全局的files,而是在GetTopXFiles内部重新生成一个。

英文:
var files fileDisplay

files is a global fileDisplay which contains a []FileDisplay that gets filled in by GetTopXFiles. But nothing updates files even if Delete is called. Thus, files is out of date after a delete, containing files that were since deleted.

The easiest solution is to not use a global files but instead regenerate one within GetTopXFiles.

huangapple
  • 本文由 发表于 2022年8月25日 19:37:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/73486783.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定