首页 > 解决方案 > go:embed 指令的问题:名称无效

问题描述

我想从我的硬盘提供音乐。所有音频文件(mp3/flac/等)都是只读的。所以使用 //go:embed 应该适用于这些文件。所以我有

//go:embed "assets/Media/Music/*"
var f embed.FS

func main() {
    router := gin.Default()

    router.StaticFS("/public", http.FS(f))
    router.GET("/", func(c *gin.Context) {
        file, _ := f.ReadFile("assets/Media/Music/<some_other_folders>/01 - my_song.mp3")
        c.Data(
            http.StatusOK,
            "audio/mpeg",
            file,
        )
    }

    router.Run(":8080")
}

问题是 Go 编译器抱怨某些文件夹名称无效,例如:“Big KRIT”和“Al B. Sure!” 文档说文件名不应该有空格或“。” 但如果我没有明确说明文件/文件夹名称,我不知道这是否适用。

我的问题是

  1. 什么构成“无效名称”
  2. 有没有办法让嵌入指令的文件夹名称带有空格

编辑

上面的代码(几乎)正是我在本地运行的。当我尝试构建(或运行 main.go)时,VS Code 会捕获此错误。结尾是文件夹名称,而不是用于说明的文件。希望这会有所帮助。提前致谢

标签: go

解决方案


查询发出错误的go命令src :invalid name

if elem := filepath.Base(dir); isBadEmbedName(elem) {
    if dir == file {
        return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
    } else {
        return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
    }
}

这引用isBadEmbedName然后依赖于函数module.CheckFilePath。此函数的文档指出:

// CheckFilePath checks that a slash-separated file path is valid.
// The definition of a valid file path is the same as the definition
// of a valid import path except that the set of allowed characters is larger:
// all Unicode letters, ASCII digits, the ASCII space character (U+0020),
// and the ASCII punctuation characters
// “!#$%&()+,-.=@[]^_{}~”.
// (The excluded punctuation characters, " * < > ? ` ' | / \ and :,
// have special meanings in certain shells or operating systems.)
//
// CheckFilePath may be less restrictive in the future, but see the
// top-level package documentation for additional information about
// subtleties of Unicode.

因此,根据最后一行,嵌入式文件名规则似乎是一个移动目标。


针对这个验证函数运行一些测试,显示出更多的微妙之处,例如dot.in.middlevs dot.at.end.

https://play.golang.org/p/7x6i_Aj8eEJ

所以这可以解释为什么你的路径Big K.R.I.T.失败了。


另外值得注意的是:当使用//go:embed带有通配符的指令时,是否会影响编译成功。

正如您所经历的,您的编译在使用时失败:

//go:embed "assets/Media/Music/*"
var f embed.FS

由于该目录中的文件名格式无效。但是,如果您删除通配符:

//go:embed "assets/Media/Music"
var f embed.FS

编译会成功——但是任何无效的文件名都会从嵌入清单中默默地删除。


如果您想明确检查程序中将嵌入哪些文件,您可以利用go list例如

go list -json

并查找EmbedFiles输出部分。或者使用jq在这部分归零:

$ go list -json | jq .EmbedFiles

[
  "Static Files/Space Dir/Big K.R.I.T.mp3",
  "Static Files/Space Dir/world.txt",
  "Static Files/hey!"
]

推荐阅读