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

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.

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