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

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

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.

  1. package fileFinder
  2. import (
  3. "fmt"
  4. "io"
  5. "io/fs"
  6. "log"
  7. "os"
  8. "sort"
  9. "sync"
  10. "github.com/google/fscrypt/filesystem"
  11. "github.com/sirupsen/logrus"
  12. )
  13. var device string
  14. type fileDisplay struct {
  15. sync.RWMutex
  16. Files []FileDisplay
  17. }
  18. var files fileDisplay
  19. type FileDisplay struct {
  20. Size int64 `json:"size"`
  21. Path string `json:"path"`
  22. }
  23. type bySize []FileDisplay
  24. func (a bySize) Len() int { return len(a) }
  25. func (a bySize) Less(i, j int) bool { return a[i].Size < a[j].Size }
  26. func (a bySize) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  27. func GetTopXFiles(mountpoint string, limit int) ([]FileDisplay, error) {
  28. log.SetOutput(io.Discard)
  29. if mountpoint == "" {
  30. return nil, fmt.Errorf("Path cannot be empty")
  31. }
  32. if limit < 1 {
  33. return nil, fmt.Errorf("Limit must be 1 or greater")
  34. }
  35. if mountpoint[len(mountpoint)-1:] != "/" {
  36. mountpoint = mountpoint + "/"
  37. }
  38. mount, err := filesystem.FindMount(mountpoint)
  39. if err != nil {
  40. return nil, err
  41. }
  42. device = mount.Device
  43. entries, err := os.ReadDir(mountpoint)
  44. if err != nil {
  45. return nil, err
  46. }
  47. var wg sync.WaitGroup
  48. getFiles(mountpoint, entries, &wg)
  49. wg.Wait()
  50. sort.Sort(bySize(files.Files))
  51. var shortFiles []FileDisplay
  52. if len(files.Files) > limit {
  53. shortFiles = files.Files[len(files.Files)-limit:]
  54. } else {
  55. shortFiles = files.Files
  56. }
  57. return shortFiles, nil
  58. }
  59. func getFiles(start string, entries []fs.DirEntry, wg *sync.WaitGroup) {
  60. for _, entry := range entries {
  61. wg.Add(1)
  62. go handleEntry(start, entry, wg)
  63. }
  64. }
  65. func handleEntry(start string, entry fs.DirEntry, wg *sync.WaitGroup) {
  66. defer wg.Done()
  67. var file FileDisplay
  68. mount, err := filesystem.FindMount(start + entry.Name())
  69. if err != nil {
  70. logrus.Errorln(err, start+entry.Name())
  71. return
  72. }
  73. if mount.Device == device {
  74. if entry.Type().IsRegular() {
  75. fileInfo, err := os.Stat(start + entry.Name())
  76. if err != nil {
  77. logrus.Errorln(err, start+entry.Name())
  78. return
  79. }
  80. file.Path = start + entry.Name()
  81. file.Size = fileInfo.Size()
  82. files.Append(file)
  83. } else if entry.IsDir() {
  84. entries, err := os.ReadDir(start + entry.Name())
  85. if err != nil {
  86. logrus.Errorln(err, start+entry.Name())
  87. return
  88. }
  89. logrus.Info("Searching ", start+entry.Name())
  90. getFiles(start+entry.Name()+"/", entries, wg)
  91. }
  92. }
  93. }
  94. func (f *FileDisplay) DisplaySizeIEC() string {
  95. const unit = 1024
  96. b := f.Size
  97. if b < unit {
  98. return fmt.Sprintf("%dB", b)
  99. }
  100. div, exp := int64(unit), 0
  101. for n := b / unit; n >= unit; n /= unit {
  102. div *= unit
  103. exp++
  104. }
  105. return fmt.Sprintf("%.2f%ciB",
  106. float64(b)/float64(div), "KMGTPE"[exp])
  107. }
  108. func (f *FileDisplay) Delete() error {
  109. err := os.Remove(f.Path)
  110. if err != nil {
  111. return err
  112. }
  113. return nil
  114. }
  115. func (fd *fileDisplay) Append(item FileDisplay) {
  116. fd.Lock()
  117. defer fd.Unlock()
  118. fd.Files = append(fd.Files, item)
  119. }

答案1

得分: 1

  1. var files fileDisplay

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

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

英文:
  1. 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:

确定