【问题标题】:Golang bad file descriptorGolang 错误的文件描述符
【发布时间】:2015-11-22 04:46:02
【问题描述】:

在我的 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
        }
    }
}()

【问题讨论】:

  • 我确认我可以在我的电脑上复制。

标签: go file-descriptor


【解决方案1】:

您需要添加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

参数标志必须包括以下访问模式之一: O_RDONLY、O_WRONLY 或 O_RDWR。这些请求打开文件读取- only、只写或读/写。

如果你检查/usr/local/go/src/syscall/zerrors_linux_amd64.go:660,你可以看到:

O_RDONLY                         = 0x0
O_RDWR                           = 0x2
O_WRONLY                         = 0x1

所以默认情况下你会得到一个只读的文件描述符。

【讨论】:

  • 这解决了我的问题,除了在我的情况下,我在包装函数的os.OpenFile 方法中有os.O_WRONLY,我从其他地方调用它并尝试从它返回的文件中读取,但当然它被设置为只写,所以我得到了同样的错误。通过更改为os.O_RDWR 修复。
【解决方案2】:

我用过

之前的代码:

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)

并没有出现问题。

【讨论】:

    【解决方案3】:

    这似乎是 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 时代以来的默认行为) Go in linux 确实需要添加额外的标志才能工作。

    (...但是 imo 它不应该需要这个标志,因为附加暗示我想写。我应该向 golang 报告这个错误吗?)

    【讨论】:

    • 欢迎来到 StackOverflow!所以你说在 Windows 上只使用 os.O_APPEND 就足够了,但对于 linux 你需要显式添加 os.O_WRONLY,对吗?请扩展您的答案,以帮助未来的访问者立即查看解决方案和调用示例(例如这样的代码在 Windows 上工作但在 Linux 上不工作,这样的代码将具有相同的行为)
    • @MaximSagaydachny 在 Windows 中是的,只是附加标志就足够了(在帖子中更新),谢谢 :)
    猜你喜欢
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 2015-05-25
    • 2015-05-20
    相关资源
    最近更新 更多