ホームページ >バックエンド開発 >Golang >埋め込みとは何ですか? Go は静的ファイルをロードするためにそれをどのように使用しますか?

埋め込みとは何ですか? Go は静的ファイルをロードするためにそれをどのように使用しますか?

藏色散人
藏色散人転載
2021-11-12 14:31:443901ブラウズ

この記事は、Golang1.16 で embed を使用して静的ファイルをロードする方法を紹介する go 言語 チュートリアル コラムによって提供されています。

#embed とは

embed は Go 1.16 で追加された新しいパッケージです。 //go:embed ディレクティブを使用して、コンパイル段階で静的リソース ファイルをコンパイル済みプログラムにパッケージ化し、これらのファイルにアクセスできるようにします。

埋め込みが必要な理由

過去には、他の言語から Go 言語に切り替えた多くの友人が尋ねたり、踏み込んだりしていました。ピット : Go 言語によってパッケージ化されたバイナリ ファイルには、構成ファイルの共同コンパイルとパッケージ化が含まれることが想定されています。

その結果、バイナリ ファイルが移動されると、静的ファイルのリソースを読み取ることができないため、アプリケーションを実行できなくなります。

静的リソースをコンパイルしてバイナリ ファイルにパッケージ化できない場合、通常は 2 つの解決策があります。

  • 1 つ目は、そのような静的リソースを特定し、プログラムに従う必要があるかどうかを確認することです。
  • 2 つ目は、バイナリ ファイルにパッケージ化することです。

2 番目のケースでは、Go は以前はこれをサポートしていなかったので、誰もが次のようなさまざまな派手なオープン ソース ライブラリを使用することになります。 しかし、Go1.16 以降、Go 言語自体がこの機能を正式にサポートしています。

これには次の利点があります。

    静的リソースをバイナリ パッケージにパッケージ化でき、デプロイメント プロセスがより簡単になります。
  • 従来のデプロイメントでは、コンパイルされたプログラムとともに静的リソースをパッケージ化してアップロードするか、dockerdockerfile を使用して前者を自動化する必要がありますが、これは非常に面倒です。
  • プログラムの整合性を確保します
  • 。動作中の静的リソースの損傷または損失は、通常、プログラムの通常の動作に影響を与えます。
  • 静的リソースへのアクセスには IO 操作はなく、速度は非常に高速になります。

embed の基本的な使用法公式ドキュメントを通じて、文字列、バイト、FS (ファイル システム) という 3 つの埋め込み方法がわかります。このうち、

string

型と []byte 型は 1 つのファイルのみに一致するため、複数のファイルまたはディレクトリに一致させたい場合は、embed.FS# を使用する必要があります。 ## タイプ。 特記事項: 埋め込みパッケージをインポートする必要があります。インポートを使用しない場合は、_ を使用してインポートしてください。

1. として埋め込みます。文字列

たとえば、現在のファイルの下にファイル hello.txt があり、ファイルの内容は

hello,world!
です。

go:embed 命令により、コンパイル後、次のプログラムの s 変数の値は hello,world! になります。

package mainimport (
    _ "embed"
    "fmt")//go:embed hello.txtvar s stringfunc main() {
    fmt.Println(s)}
2. バイト スライスとして埋め込む

単一ファイルの内容をバイトのスライス (バイト配列) として埋め込むこともできます。

package mainimport (
    _ "embed"
    "fmt")//go:embed hello.txtvar b []bytefunc main() {
    fmt.Println(b)}

3. fs.FS

として埋め込む ファイル システムとして埋め込むこともでき、複数のファイルを埋め込む場合に非常に便利です。


たとえば、ファイルを埋め込みます:

package mainimport (
    "embed"
    "fmt")//go:embed hello.txtvar f embed.FSfunc main() {
    data, _ := f.ReadFile("hello.txt")
    fmt.Println(string(data))}
別のローカル ファイル hello2.txt を埋め込み、同じ変数に対する複数の

go:embed

命令をサポートします (文字列または A として埋め込みます)バイト スライスには複数の

go:embed 命令を含めることはできません):

package mainimport (
    "embed"
    "fmt")//go:embed hello.txt//go:embed hello2.txtvar f embed.FSfunc main() {
    data, _ := f.ReadFile("hello.txt")
    fmt.Println(string(data))
    data, _ = f.ReadFile("hello2.txt")
    fmt.Println(string(data))}
現在繰り返されている go:embed 命令の embed.FS への埋め込みがサポートされています。

package mainimport (
    "embed"
    "fmt")//go:embed hello.txt//go:embed hello.txtvar f embed.FSfunc main() {
    data, _ := f.ReadFile("hello.txt")
    fmt.Println(string(data))}
サブフォルダーにファイルを埋め込むこともできます:
package mainimport (
    "embed"
    "fmt")//go:embed p/hello.txt//go:embed p/hello2.txtvar f embed.FSfunc main() {
    data, _ := f.ReadFile("p/hello.txt")
    fmt.Println(string(data))
    data, _ = f.ReadFile("p/hello2.txt")
    fmt.Println(string(data))}

embed高度な使用法

Go1.16 を embed ## にサポートするには# は新しいパッケージ

io/fs

にも追加されました。 2 つを結合すると、以前の通常のファイルと同じように操作できます。 1. 読み取り専用

埋め込まれたコンテンツは読み取り専用です。つまり、コンパイル時の埋め込みファイルの内容は何か、次に実行時の内容は何かということです。 FS ファイル システムの値は、オープンおよび読み取りのメソッドを提供しますが、書き込みメソッドはありません。これは、FS インスタンスがスレッドセーフであり、複数の goroutine を同時に使用できることを意味します。

embed.FS 構造には、主に次の 3 つの外部メソッドがあります:

// Open 打开要读取的文件,并返回文件的fs.File结构.func (f FS) Open(name string) (fs.File, error)// ReadDir 读取并返回整个命名目录func (f FS) ReadDir(name string) ([]fs.DirEntry, error)// ReadFile 读取并返回name文件的内容.func (f FS) ReadFile(name string) ([]byte, error)

2. 複数のファイルを埋め込む

package mainimport (
    "embed"
    "fmt")//go:embed hello.txt hello2.txtvar f embed.FSfunc main() {
    data, _ := f.ReadFile("hello.txt")
    fmt.Println(string(data))

    data, _ = f.ReadFile("hello2.txt")
    fmt.Println(string(data))}
もちろん、前の例のように複数行を記述することもできます go:embed

:
package mainimport (
    "embed"
    "fmt")//go:embed hello.txt//go:embed hello2.txtvar f embed.FSfunc main() {
    data, _ := f.ReadFile("hello.txt")
    fmt.Println(string(data))
    data, _ = f.ReadFile("hello2.txt")
    fmt.Println(string(data))}

3. フォルダー分離のサポート

文字は使用しますスラッシュ /

、Windows システムでもこのパターンが使用されます。
package mainimport (
    "embed"
    "fmt")//go:embed pvar f embed.FSfunc main() {
    data, _ := f.ReadFile("p/hello.txt")
    fmt.Println(string(data))
    data, _ = f.ReadFile("p/hello2.txt")
    fmt.Println(string(data))}

应用

在我们的项目中,是将应用的常用的一些配置写在了.env的一个文件上,所以我们在这里就可以使用go:embed指令。

main.go 文件:

//go:embed ".env" "v1d0/.env"var FS embed.FSfunc main(){
    setting.InitSetting(FS)
    manager.InitManager()
    cron.InitCron()
    routersInit := routers.InitRouter()
    readTimeout := setting.ServerSetting.ReadTimeout
    writeTimeout := setting.ServerSetting.WriteTimeout
    endPoint := fmt.Sprintf(":%d", setting.ServerSetting.HttpPort)
    maxHeaderBytes := 1 << 20
    server := &http.Server{
        Addr:           endPoint,
        Handler:        routersInit,
        ReadTimeout:    readTimeout,
        WriteTimeout:   writeTimeout,
        MaxHeaderBytes: maxHeaderBytes,
    }
    server.ListenAndServe()}

setting.go文件:

func InitSetting(FS embed.FS) {
    // 总配置处理
    var err error
    data, err := FS.ReadFile(".env")
    if err != nil {
        log.Fatalf("Fail to parse '.env': %v", err)
    }
    cfg, err = ini.Load(data)
    if err != nil {
        log.Fatal(err)
    }
    mapTo("server", ServerSetting)
    ServerSetting.ReadTimeout  = ServerSetting.ReadTimeout * time.Second
    ServerSetting.WriteTimeout = ServerSetting.WriteTimeout * time.Second    // 分版本配置引入
    v1d0Setting.InitSetting(FS)}

以上が埋め込みとは何ですか? Go は静的ファイルをロードするためにそれをどのように使用しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。