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

时间:2014-08-27 18:48:58

标签: go

我有很多记录器在我的应用程序中写入不同的文件。我正在尝试添加在应用程序运行时截断该文件的功能。这就是我所拥有的:

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
}

这使我可以轻松地记录每个资源一个文件。但是,当我尝试使用Resource.Logger.LogFile.Truncate(0)时,我收到拒绝访问错误。

1 个答案:

答案 0 :(得分:1)

我认为你在Windows上工作,因为Windows有像这样的锁定文件的习惯。我建议,既然你基本上可以控制日志写入和截断,你可以暂时关闭文件,然后在没有打开文件句柄的情况下截断它。

您必须使用例如互斥锁来阻止任何人在您截断时尝试记录任何内容,并在完成后重新打开日志文件以进行写入。这是一个粗略的例子:

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