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

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

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()
}
}

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:

确定