尝试在go例程中追加日志文件时,我收到了错误的文件描述符。
write ./log.log: bad file descriptor
该文件存在且具有666权限。起初我认为可能是因为他们每个人都试图同时打开文件。我实现了一个互斥锁,试图避免这种情况,但是遇到了同样的问题,所以我删除了它。
logCh := make(chan string, 150)
go func() {
for {
msg, ok := <-logCh
if ok {
if f, err := os.OpenFile("./log.log", os.O_APPEND, os.ModeAppend); err != nil {
panic(err)
} else {
logTime := time.Now().Format(time.RFC3339)
if _, err := f.WriteString(logTime + " - " + msg); err != nil {
fmt.Print(err)
}
f.Close()
}
} else {
fmt.Print("Channel closed! \n")
break
}
}
}()
答案 0 :(得分:30)
您需要添加O_WRONLY
标志:
if f, err := os.OpenFile("./log.log", os.O_APPEND|os.O_WRONLY, os.ModeAppend); err != nil { /*[...]*/ }
要解释一下,这是open的开放式文档:http://man7.org/linux/man-pages/man2/openat.2.html:
参数标志必须包含以下访问模式之一: O_RDONLY,O_WRONLY或O_RDWR。这些请求打开文件读取 - 只有,只写或读/写。
如果你查看/usr/local/go/src/syscall/zerrors_linux_amd64.go:660,你可以看到:
O_RDONLY = 0x0
O_RDWR = 0x2
O_WRONLY = 0x1
因此,默认情况下,您将获得只读文件描述符。
答案 1 :(得分:1)
这似乎是Windows和Linux之间的差异。 在Windows上,os.O_APPEND表示写访问权限,如syscall_windows.go中的代码所示。
if mode&O_APPEND != 0 {
access &^= GENERIC_WRITE
access |= FILE_APPEND_DATA
}
在linux中,openflags原样传递给linux系统调用
因此,在DOS / WINDOWS中,您不需要显式添加带有附加标志的写标志,因为这是隐含的。 (这是自DOS以来的默认行为) 在Linux中运行确实需要添加额外的标志才能工作。
(...但是imo不应 该标志,因为隐式附加意味着我要写。我应该将其错误报告给golang吗?)
答案 2 :(得分:0)
对我有用
之前的代码:
os.OpenFile(fileName, os.O_CREATE|os.O_APPEND, os.ModePerm)
并发生错误:错误的文件描述符,
然后我将os.O_WRONLY添加到函数中
后面的代码:
os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
它并没有出现问题。