golang os.Create引发“没有该文件或目录”错误。

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

golang os.Create cause "no such file or directory" error

问题

一定是有什么简单的问题,但我似乎无法弄清楚。我一直收到“没有这样的文件或目录”错误。我以为Create函数是用来创建新文件的?

package main

import (
    "log"
	"os"
)

func main() {
	f, err := os.Create("~/golang-server.log")
	defer f.Close()
	if err != nil {
	    panic(err.Error())
	}
	log.SetOutput(f)
}
英文:

Must be something simple, but I cannot seem to figure out. I keep getting "no such file or directory" error. Thought the Create function is to create a new file?

package main

import (
    "log"
	"os"
)

func main() {
	f, err := os.Create("~/golang-server.log")
	defer f.Close()
	if err != nil {
	    panic(err.Error())
	}
	log.SetOutput(f)
}

</details>


# 答案1
**得分**: 5

你不能使用`~`或环境变量`$HOME`来指定文件路径它们是字符串字面量表示实际路径你得到的错误是因为它将`~/golang-server.log`视为当前目录的相对路径而当前目录中没有名为`~`的目录

通过手动创建子目录`~`你的代码将成功运行

     ~/test/ mkdir \~
     ~/test/ go run t.go
     ~/test/ ls \~
    golang-server.log

因此需要传递一个`绝对路径``相对路径``os.Create`

<details>
<summary>英文:</summary>

You can&#39;t use `~` or environment variable like `$HOME` to specify the file path, they&#39;re string literal and means actual path. The error you got is because it treat `~/golang-server.log` as a relative path of current directory, and there&#39;s no directory `~` in current directory.

With manually created sub-directory `~`, your code will succeed:

     ~/test/ mkdir \~
     ~/test/ go run t.go
     ~/test/ ls \~
    golang-server.log

So need to pass an `absolute path` or `relative path` to `os.Create`.

</details>



# 答案2
**得分**: 4

你可以使用`os.ExpandEnv`来处理在sh/bash上下文中才有意义的"~"符号

```go
os.Create(os.ExpandEnv("$HOME/golang-server.log"))

在更复杂的情况下,你需要确保基础目录存在,因为os.Create不会处理它。

这就是为什么os.Create("~/golang-server.log")会失败的原因,因为基础目录不存在,而os.Create不会自动为你创建它。你需要像这样自己创建:

func EnsureBaseDir(fpath string) error {
    baseDir := path.Dir(fpath)
    info, err := os.Stat(baseDir)
    if err == nil && info.IsDir() {
        return nil
    }
    return os.MkdirAll(baseDir, 0755)
}

注意:

  • $HOME并不总是存在,例如程序作为系统级别的systemd服务运行。因此,在生产环境中最好不要使用$HOME
  • os.Create的限制不仅存在于Go中,它是由操作系统内核引起的,在其他语言/标准库中也广泛存在。
英文:

You can use os.ExpandEnv to handle the "~" which is only make sense in sh/bash context.

os.Create(os.ExpandEnv(&quot;$HOME/golang-server.log&quot;))

In more complicated cases, you need to ensure that the base directory exists, because os.Create does not handle it.

And this is the reason why os.Create(&quot;~/golang-server.log&quot;) will fail, because the base directory doesn't exist and os.Create wouldn't automatically create it for you. You need do it by yourself like this:

func EnsureBaseDir(fpath string) error {
baseDir := path.Dir(fpath)
info, err := os.Stat(baseDir)
if err == nil &amp;&amp; info.IsDir() {
return nil
}
return os.MkdirAll(baseDir, 0755)
}

NOTE:

  • $HOME is not always exists, e.g. the program run as a system level systemd service. So you better not use $HOME in a production environment.
  • the limitation of os.Create doesn't only exist in Go. It's caused by the OS kernel and widely exists in other languages/stdlib.

huangapple
  • 本文由 发表于 2017年4月11日 10:53:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/43335989.html
匿名

发表评论

匿名网友

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

确定