英文:
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论