Golang 错误的文件描述符
Golang bad file descriptor
在我的 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
}
}
}()
您需要添加 O_WRONLY
标志:
if f, err := os.OpenFile("./log.log", os.O_APPEND|os.O_WRONLY, os.ModeAppend); err != nil { /*[...]*/ }
为了解释,这里是 open
的 linux 文档:http://man7.org/linux/man-pages/man2/openat.2.html :
The argument flags must include one of the following access modes:
O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read-
only, write-only, or read/write, respectively.
如果您检查 /usr/local/go/src/syscall/zerrors_linux_amd64.go:660,您会看到:
O_RDONLY = 0x0
O_RDWR = 0x2
O_WRONLY = 0x1
所以默认情况下你得到一个只读文件描述符。
我用过
之前的代码:
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)
并没有出现问题。
这似乎是 windows 和 linux 之间的差异。
On 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 确实需要添加额外的标志才能工作。
(...但是我不应该 需要 这个标志,因为附加隐含地暗示我想写。我应该向 golang 报告这个错误吗?)
在我的 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
}
}
}()
您需要添加 O_WRONLY
标志:
if f, err := os.OpenFile("./log.log", os.O_APPEND|os.O_WRONLY, os.ModeAppend); err != nil { /*[...]*/ }
为了解释,这里是 open
的 linux 文档:http://man7.org/linux/man-pages/man2/openat.2.html :
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read- only, write-only, or read/write, respectively.
如果您检查 /usr/local/go/src/syscall/zerrors_linux_amd64.go:660,您会看到:
O_RDONLY = 0x0
O_RDWR = 0x2
O_WRONLY = 0x1
所以默认情况下你得到一个只读文件描述符。
我用过
之前的代码:
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)
并没有出现问题。
这似乎是 windows 和 linux 之间的差异。 On 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 确实需要添加额外的标志才能工作。
(...但是我不应该 需要 这个标志,因为附加隐含地暗示我想写。我应该向 golang 报告这个错误吗?)