截断打开的 os.File(访问被拒绝)

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

Truncating open os.File (access denied)

问题

我在我的应用程序中有许多记录器,它们写入不同的文件。我正在尝试在应用程序运行时添加截断文件的功能。以下是我的代码:

  1. type Resource struct {
  2. Logger *ResourceLogger
  3. // 其他与资源相关的内容...
  4. }
  5. func (r *Resource) SetLogger(logPath string) {
  6. path := logPath + r.Name + ".log"
  7. f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
  8. if err != nil {
  9. log.Fatalf("无法打开日志文件 '%v'", path)
  10. }
  11. r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f}
  12. }
  13. type ResourceLogger struct {
  14. *log.Logger
  15. LogFile *os.File
  16. }

这样我就可以轻松地将日志记录到多个文件中,每个资源一个文件。然而,当我尝试使用 Resource.Logger.LogFile.Truncate(0) 时,我会收到一个访问被拒绝的错误。

英文:

I have many loggers that write to a different file in my application. I'm trying to add in the ability to truncate that file while the application is running. Here is what I have:

  1. type Resource struct {
  2. Logger *ResourceLogger
  3. // other stuff pertaining to my resource...
  4. }
  5. func (r *Resource) SetLogger(logPath string) {
  6. path := logPath + r.Name + ".log"
  7. f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
  8. if err != nil {
  9. log.Fatalf("Unable to open log file '%v'", path)
  10. }
  11. r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f}
  12. }
  13. type ResourceLogger struct {
  14. *log.Logger
  15. LogFile *os.File
  16. }

This allows me to log to many files, one per resource with ease. However, when I try to use Resource.Logger.LogFile.Truncate(0) I get an access denied error.

答案1

得分: 1

我猜你正在使用Windows,因为Windows有锁定文件的习惯。我建议你在截断文件时,先关闭文件一小段时间,然后在没有打开文件句柄的情况下进行截断。

你可以使用互斥锁(mutex)来阻止任何人在截断期间尝试记录任何内容,并在完成后重新打开日志文件进行写入。这里有一个简单的示例代码:

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "sync"
  6. )
  7. type Resource struct {
  8. Logger *ResourceLogger
  9. // 其他与资源相关的内容...
  10. Name string
  11. }
  12. func (r *Resource) SetLogger(logPath string) {
  13. path := logPath + r.Name + ".log"
  14. f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
  15. if err != nil {
  16. log.Fatalf("无法打开日志文件 '%v'", path)
  17. }
  18. r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f, path, sync.Mutex{}}
  19. }
  20. func (r *ResourceLogger) Truncate() {
  21. if r.logger != nil {
  22. r.logmutex.Lock()
  23. r.logfile.Close()
  24. os.Truncate(r.logfilename, 0) // 文件在Windows上不能打开!
  25. f, err := os.OpenFile(r.logfilename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
  26. if err != nil {
  27. log.Fatalf("无法打开日志文件 '%v'", r.logfilename)
  28. }
  29. r.logger = log.New(f, "", log.Ldate|log.Ltime)
  30. r.logfile = f
  31. r.logmutex.Unlock()
  32. }
  33. }
  34. type ResourceLogger struct {
  35. logger *log.Logger
  36. logfile *os.File
  37. logfilename string
  38. logmutex sync.Mutex
  39. }
  40. func (r *ResourceLogger) Println(s string) {
  41. r.logmutex.Lock()
  42. r.logger.Println(s)
  43. r.logmutex.Unlock()
  44. }
  45. func main() {
  46. r := Resource{}
  47. r.Name = "jeejee"
  48. r.SetLogger("")
  49. r.Logger.Println("测试一")
  50. for {
  51. r.Logger.Println("更多日志记录")
  52. r.Logger.Truncate()
  53. }
  54. }

希望对你有帮助!

英文:

I take it you are working on Windows, because Windows has the habbit of locking files just like that. I would suggest that since you basically can control both log writing and truncating, you can close the file for a split second and then truncate it while there are no open file handles.

You have to use for instance a mutex to stop anyone from attempting to log anything while you are truncating, and simply re-open the log file for writing after you are done. Here's a rough example for you:

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "sync"
  6. )
  7. type Resource struct {
  8. Logger *ResourceLogger
  9. // other stuff pertaining to my resource...
  10. Name string
  11. }
  12. func (r *Resource) SetLogger(logPath string) {
  13. path := logPath + r.Name + ".log"
  14. f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
  15. if err != nil {
  16. log.Fatalf("Unable to open log file '%v'", path)
  17. }
  18. r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f, path, sync.Mutex{}}
  19. }
  20. func (r *ResourceLogger) Truncate() {
  21. if r.logger != nil {
  22. r.logmutex.Lock()
  23. r.logfile.Close()
  24. os.Truncate(r.logfilename, 0) // The file must not be open on Windows!
  25. f, err := os.OpenFile(r.logfilename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
  26. if err != nil {
  27. log.Fatalf("Unable to open log file '%v'", r.logfilename)
  28. }
  29. r.logger = log.New(f, "", log.Ldate|log.Ltime)
  30. r.logfile = f
  31. r.logmutex.Unlock()
  32. }
  33. }
  34. type ResourceLogger struct {
  35. logger *log.Logger
  36. logfile *os.File
  37. logfilename string
  38. logmutex sync.Mutex
  39. }
  40. func (r *ResourceLogger) Println(s string) {
  41. r.logmutex.Lock()
  42. r.logger.Println(s)
  43. r.logmutex.Unlock()
  44. }
  45. func main() {
  46. r := Resource{}
  47. r.Name = "jeejee"
  48. r.SetLogger("")
  49. r.Logger.Println("test one")
  50. for {
  51. r.Logger.Println("more logging")
  52. r.Logger.Truncate()
  53. }
  54. }

huangapple
  • 本文由 发表于 2014年8月28日 02:48:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/25534857.html
匿名

发表评论

匿名网友

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

确定