Golang中如何加载包含多个文件的embed库

Golang中如何加载包含多个文件的embed库

//go:embed sqls/allquery.sql

我正在使用第三方库 sqload,它目前仅支持单个文件。

如何实现支持多个文件?

4 回复

谢谢。我之前尝试通过添加 *.SQL 并使用单个变量来实现。

更多关于Golang中如何加载包含多个文件的embed库的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


您也可以使用通配符进行嵌入,例如 ./*.sql。 此时变量必须是 embed.FS 类型。

参见:Go by Example: Embed Directive

除非我误解了你的问题(因为我不熟悉 sqload 库),否则这很简单,只需嵌入多个文件并使用它们即可。

//go:embed sqls/allquery.sql
var allQuery string

//go:embed sqls/someotherquery.sql
var someOtherQuery string

var q1 = sqload.MustLoadFromString[struct {
	...
}](allQuery)

var q2 = sqload.MustLoadFromString[struct {
	...
}](someOtherQuery)

在Golang中加载包含多个文件的embed库,可以使用//go:embed指令配合通配符模式。以下是几种实现方式:

1. 使用通配符嵌入整个目录

import "embed"

//go:embed sqls/*.sql
var sqlFiles embed.FS

// 读取所有SQL文件
func loadAllSQLFiles() error {
    entries, err := sqlFiles.ReadDir("sqls")
    if err != nil {
        return err
    }
    
    for _, entry := range entries {
        if !entry.IsDir() {
            data, err := sqlFiles.ReadFile("sqls/" + entry.Name())
            if err != nil {
                return err
            }
            fmt.Printf("Loaded %s: %s\n", entry.Name(), string(data))
        }
    }
    return nil
}

2. 嵌入特定文件列表

import "embed"

//go:embed sqls/query1.sql sqls/query2.sql sqls/query3.sql
var sqlFiles embed.FS

// 读取特定文件
func getSQLContent(filename string) (string, error) {
    data, err := sqlFiles.ReadFile(filename)
    if err != nil {
        return "", err
    }
    return string(data), nil
}

3. 嵌入子目录及其所有内容

import "embed"

//go:embed sqls
var sqlDir embed.FS

// 递归读取所有文件
func walkSQLFiles() error {
    return fs.WalkDir(sqlDir, ".", func(path string, d fs.DirEntry, err error) error {
        if err != nil {
            return err
        }
        if !d.IsDir() {
            data, err := sqlDir.ReadFile(path)
            if err != nil {
                return err
            }
            fmt.Printf("File: %s\nContent: %s\n", path, string(data))
        }
        return nil
    })
}

4. 为sqload库创建适配器

如果sqload只支持单个文件,可以创建一个包装器:

import (
    "embed"
    "strings"
    "github.com/thirdparty/sqload"
)

//go:embed sqls/*.sql
var sqlFS embed.FS

type MultiFileLoader struct {
    fs embed.FS
    dir string
}

func NewMultiFileLoader(fs embed.FS, dir string) *MultiFileLoader {
    return &MultiFileLoader{fs: fs, dir: dir}
}

func (m *MultiFileLoader) LoadAll() (map[string]string, error) {
    queries := make(map[string]string)
    
    entries, err := m.fs.ReadDir(m.dir)
    if err != nil {
        return nil, err
    }
    
    for _, entry := range entries {
        if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".sql") {
            data, err := m.fs.ReadFile(m.dir + "/" + entry.Name())
            if err != nil {
                return nil, err
            }
            
            // 使用文件名(不含扩展名)作为key
            name := strings.TrimSuffix(entry.Name(), ".sql")
            queries[name] = string(data)
            
            // 如果需要,也可以直接初始化sqload
            // loader := sqload.New(string(data))
        }
    }
    
    return queries, nil
}

// 使用示例
func main() {
    loader := NewMultiFileLoader(sqlFS, "sqls")
    queries, err := loader.LoadAll()
    if err != nil {
        panic(err)
    }
    
    // 现在可以使用queries map中的SQL语句
    for name, sql := range queries {
        fmt.Printf("Query %s: %s\n", name, sql)
    }
}

5. 合并多个SQL文件为单个字符串

如果sqload必须使用单个字符串:

import (
    "embed"
    "strings"
)

//go:embed sqls/*.sql
var sqlFS embed.FS

func combineSQLFiles() (string, error) {
    var builder strings.Builder
    
    entries, err := sqlFS.ReadDir("sqls")
    if err != nil {
        return "", err
    }
    
    for _, entry := range entries {
        if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".sql") {
            data, err := sqlFS.ReadFile("sqls/" + entry.Name())
            if err != nil {
                return "", err
            }
            builder.WriteString("-- " + entry.Name() + "\n")
            builder.Write(data)
            builder.WriteString("\n\n")
        }
    }
    
    return builder.String(), nil
}

// 然后使用合并后的字符串初始化sqload
// combinedSQL, _ := combineSQLFiles()
// loader := sqload.New(combinedSQL)

这些方法提供了从嵌入多个文件到适应单文件库的不同解决方案。选择哪种方式取决于你的具体需求和对sqload库的使用方式。

回到顶部