Golang坏文件描述符

huangapple go评论89阅读模式
英文:

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
        }
    }
}()
英文:

I am getting a bad file descriptor when trying to append to a logging file within my go routine.

write ./log.log: bad file descriptor

The file exists and has 666 for permissions. At first I thought well maybe it is because each one of them is trying to open the file at the same time. I implemented a mutex to try and avoid that but got the same issue so I removed it.

logCh := make(chan string, 150)
go func() {
	for {
		msg, ok := &lt;-logCh
		if ok {
			if f, err := os.OpenFile(&quot;./log.log&quot;, os.O_APPEND, os.ModeAppend); err != nil {
				panic(err)
			} else {
				logTime := time.Now().Format(time.RFC3339)
				if _, err := f.WriteString(logTime + &quot; - &quot; + msg); err != nil {
					fmt.Print(err)
				}
				f.Close()
			}
		} else {
			fmt.Print(&quot;Channel closed! \n&quot;)
			break
		}
	}
}()

答案1

得分: 107

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

参数flags必须包含以下访问模式之一:O_RDONLYO_WRONLYO_RDWR。它们分别表示只读、只写或读写模式。

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

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

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

英文:

You need to add the O_WRONLY flag :

if f, err := os.OpenFile(&quot;./log.log&quot;, os.O_APPEND|os.O_WRONLY, os.ModeAppend); err != nil { /*[...]*/ }

To explain, here is the linux documentation for open: 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.

If you check /usr/local/go/src/syscall/zerrors_linux_amd64.go:660, you can see that:

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

So by default you get a read-only file descriptor.

答案2

得分: 3

这似乎是Windows和Linux之间的差异。

在Windows操作系统中,O_APPEND意味着写访问权限,可以在syscall_windows.go代码中看到。

if mode&amp;O_APPEND != 0 {
	access &amp;^= GENERIC_WRITE
	access |= FILE_APPEND_DATA
}

在Linux中,openflags原样传递给Linux系统调用。

因此,在DOS / WINDOWS中,您不需要显式添加写标志和追加标志,因为它是隐含的(自DOS时代以来一直是默认行为)。
在Linux中,Go需要添加额外的标志才能正常工作。

(...但我认为它不应该“需要”这个标志,因为追加隐含地意味着我想要写入。我应该向golang报告这个问题吗?)

英文:

This appears to be a discrepancy between windows and linux.
On windows os.O_APPEND implies write access, as can be seen in the code in syscall_windows.go.

if mode&amp;O_APPEND != 0 {
	access &amp;^= GENERIC_WRITE
	access |= FILE_APPEND_DATA
}

in linux the openflags are passed as-is to a linux syscall

So in DOS/WINDOWS you do not need to explicitly add a write flag with an append flag, as it is implied. (this has been default behaviour since the DOS days)
Go in linux does need the extra flag added to work.

(...but imo it should not need this flag, as appending implicitly implies that I want to write. Should I bugreport this to golang ?)

答案3

得分: 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)

这样就没有出现问题了。

英文:

it used for me

the code before:

os.OpenFile(fileName, os.O_CREATE|os.O_APPEND, os.ModePerm)

and it occured the error: bad file descriptor,

then i add the os.O_WRONLY into the function

the code after:

os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)

and it did't occured the problem.

huangapple
  • 本文由 发表于 2015年11月22日 12:46:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/33851692.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定