zoukankan      html  css  js  c++  java
  • golang官方嵌入文件到可执行程序

    前言

    在go官方出嵌入文件的方法前我在网上找过,并且自己还研究过,虽然没有问题,但是既然官方支持还是用起来吧。
    看了下go源码embed/embed.go很简单,并且看embed/internal/embedtest/embed_test.go就知道如何使用。

    示例程序

    嵌入文件直接访问

    原理是使用go:embed标签来完成。下面是直接读取文件内容,需要注意下面几点。
    文件不是utf8编码时,输出内容为中文会乱码。
    测试过嵌入文件只能为源码文件同级目录和子目录下的文件,试过其他目录的绝对路径或相对路径会报错。
    如果路径包含空格可以使用双引号或反引号括起来。
    变量的类型只能是string、[]byte、embed.FS,即使是这三个类型的别名也不行。
    我测试过几个能想到的场景,有些会报错,所以在使用时需要注意。

    package main
    
    import (
        _ "embed"
    )
    
    //go:embed test.txt
    var testString string  // 当前目录,解析为string类型
    
    //go:embed test.txt
    var testByte []byte  // 当前目录,解析为[]byte类型
    
    //go:embed test/test.txt
    var testAbsolutePath string  // 子目录,解析为string类型
    
    //go:embed notExistsFile
    var testErr0 string // 文件不存在,编译报错:pattern notExistsFile: no matching files found
    
    //go:embed dir
    var testErr1 string // dir是目录,编译报错:pattern dir: cannot embed directory dir: contains no embeddable files
    
    //go:embed ../test.txt
    var testErr2 string // 相对路径,不是当前目录或子目录,编译报错:pattern ../test.txt: invalid pattern syntax
    
    //go:embed D:	est.txt
    var testErr3 string // 绝对路径,编译报错:pattern D:	est.txt: no matching files found
    
    func main() {
        println(testString)
        println(string(testByte))
        println(testAbsolutePath)
    }
    

    嵌入文件列表

    package main
    
    import (
        "embed"
        "io"
        "os"
    )
    
    //go:embed test0.txt test1.txt test1*.txt
    //go:embed test/test0.txt test/test1.txt
    //go:embed test0
    var fileList embed.FS
    /*
    使用上述方法可以将多个文件或目录添加到fileList中。
    1. 添加多个文件,且支持"*"号通配文件。
    2. 支持子目录文件。
    3. 支持嵌入一个目录。
    */
    
    func main() {
        testDir, err := fileList.ReadDir("test0")
        if err != nil {
            panic(err)
        }
        for _, v := range testDir {
            println(v.Name()) // 打印嵌入的目录内容
        }
    
        // 使用fileList.Open可以生成一个对象,可以通过文件流那样读出来
        testFile, err := fileList.Open("test0.txt")
        if err != nil {
            panic(err)
        }
        io.Copy(os.Stdout, testFile)
    
        testFile, err = fileList.Open("test112.txt")
        if err != nil {
            panic(err)
        }
        io.Copy(os.Stdout, testFile)
    
        testFile, err = fileList.Open("test/test1.txt")
        if err != nil {
            panic(err)
        }
        io.Copy(os.Stdout, testFile)
    
        // 直接将文件内容读出来
        data, err := fileList.ReadFile("test111.txt")
        if err != nil {
            panic(err)
        }
        println(string(data))
    }
    

    嵌入http服务器

    以前都需要将http服务器和文件都部署,现在可以直接使用,而且也超级方便。

    package main
    
    import (
        "embed"
        "net/http"
    )
    
    //go:embed test0.txt test1.txt test1*.txt
    //go:embed test/test0.txt test/test1.txt
    //go:embed test0
    var fileList embed.FS
    
    func main() {
        http.Handle("/", http.FileServer(http.FS(fileList)))
        http.ListenAndServe(":8080", nil)
    }
    

    下面是web访问结果:

    总结

    今天看到go1.16发布,看了下特性,支持嵌入文件到可执行程序中,所以研究了一下。
    我发现直接看源码的_test测试文件就知道是如何使用的,都不需要到处搜教程。
    所以说学习要知其然且知其所以然,不然天天搜别人的示例代码,却不知道原理,是不能灵活使用的。

    作者:janbar
    本文版权归作者和博客园所有,欢迎转载,转载请标明出处。喜欢我的文章请 [关注我] 吧。
    如果您觉得本篇博文对您有所收获,可点击 [推荐] [收藏] ,或到右侧 [打赏] 里请我喝杯咖啡,非常感谢。
  • 相关阅读:
    shell 中"${b2}" and "${b:2}"
    关于 libpcap的安装
    ubuntu adsl 上网
    2011.1.18 运算符优先级
    Tail Queues
    fd_set struct
    读取和修改操作array 配置文件的方法
    smarty调试方法
    一个CURL例子
    cakephp数据库事务transactions
  • 原文地址:https://www.cnblogs.com/janbar/p/14412784.html
Copyright © 2011-2022 走看看