英文:
Truncating open os.File (access denied)
问题
我在我的应用程序中有许多记录器,它们写入不同的文件。我正在尝试在应用程序运行时添加截断文件的功能。以下是我的代码:
type Resource struct {
Logger *ResourceLogger
// 其他与资源相关的内容...
}
func (r *Resource) SetLogger(logPath string) {
path := logPath + r.Name + ".log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("无法打开日志文件 '%v'", path)
}
r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f}
}
type ResourceLogger struct {
*log.Logger
LogFile *os.File
}
这样我就可以轻松地将日志记录到多个文件中,每个资源一个文件。然而,当我尝试使用 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:
type Resource struct {
Logger *ResourceLogger
// other stuff pertaining to my resource...
}
func (r *Resource) SetLogger(logPath string) {
path := logPath + r.Name + ".log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Unable to open log file '%v'", path)
}
r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f}
}
type ResourceLogger struct {
*log.Logger
LogFile *os.File
}
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)来阻止任何人在截断期间尝试记录任何内容,并在完成后重新打开日志文件进行写入。这里有一个简单的示例代码:
package main
import (
"log"
"os"
"sync"
)
type Resource struct {
Logger *ResourceLogger
// 其他与资源相关的内容...
Name string
}
func (r *Resource) SetLogger(logPath string) {
path := logPath + r.Name + ".log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("无法打开日志文件 '%v'", path)
}
r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f, path, sync.Mutex{}}
}
func (r *ResourceLogger) Truncate() {
if r.logger != nil {
r.logmutex.Lock()
r.logfile.Close()
os.Truncate(r.logfilename, 0) // 文件在Windows上不能打开!
f, err := os.OpenFile(r.logfilename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("无法打开日志文件 '%v'", r.logfilename)
}
r.logger = log.New(f, "", log.Ldate|log.Ltime)
r.logfile = f
r.logmutex.Unlock()
}
}
type ResourceLogger struct {
logger *log.Logger
logfile *os.File
logfilename string
logmutex sync.Mutex
}
func (r *ResourceLogger) Println(s string) {
r.logmutex.Lock()
r.logger.Println(s)
r.logmutex.Unlock()
}
func main() {
r := Resource{}
r.Name = "jeejee"
r.SetLogger("")
r.Logger.Println("测试一")
for {
r.Logger.Println("更多日志记录")
r.Logger.Truncate()
}
}
希望对你有帮助!
英文:
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:
package main
import (
"log"
"os"
"sync"
)
type Resource struct {
Logger *ResourceLogger
// other stuff pertaining to my resource...
Name string
}
func (r *Resource) SetLogger(logPath string) {
path := logPath + r.Name + ".log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Unable to open log file '%v'", path)
}
r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f, path, sync.Mutex{}}
}
func (r *ResourceLogger) Truncate() {
if r.logger != nil {
r.logmutex.Lock()
r.logfile.Close()
os.Truncate(r.logfilename, 0) // The file must not be open on Windows!
f, err := os.OpenFile(r.logfilename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Unable to open log file '%v'", r.logfilename)
}
r.logger = log.New(f, "", log.Ldate|log.Ltime)
r.logfile = f
r.logmutex.Unlock()
}
}
type ResourceLogger struct {
logger *log.Logger
logfile *os.File
logfilename string
logmutex sync.Mutex
}
func (r *ResourceLogger) Println(s string) {
r.logmutex.Lock()
r.logger.Println(s)
r.logmutex.Unlock()
}
func main() {
r := Resource{}
r.Name = "jeejee"
r.SetLogger("")
r.Logger.Println("test one")
for {
r.Logger.Println("more logging")
r.Logger.Truncate()
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论