go代码中需要path中存在某些二进制文件,怎么一起打包

背景

go代码里面需要在环境变量path中有某些二进制文件才能运行成功,否则会有运行时错误。

先说下需求背景,业务需要有个地方需要解析音频视频图片的分辨率和长度等信息。经过不懈的搜索发现ffmpeg可以完成以上需求。

秉承着能用就行的原则在github上随便选择了一个go相关的ffmpeg的仓库,

github上的ffmpeg-go仓库,顺路贴在这里。

但是运行demo的时候发现还要安装ffmpeg,否则就会报没有找到相关文件的错误,windows就是解压ffmpeg相关二进制文件,直接放到path中,或者运行程序同级目录就好了。官方下载地址这里也贴一下:Download FFmpeg里面包含linux,windows,mac的下载。

新的问题又出现了,go本来可以是一个二进制文件就能运行,可否把这些二进制一起打包进编译好的文件中,这样其他人拿到二进制文件就能直接运行。(当然也可以一起把二进制文件给他)今天我们就尝试一起打包进一个二进制文件中。

解决

利用go 1.16新特性embed包在编译阶段将静态资源文件打包进编译好的程序中,并提供访问这些文件的能力。

加上go条件编译。就是在文件头加上 // go:build windows 这样。

就是给不同的环境编译的时候打包进去不同的文件。

然后运行的时候再解压出来,和运行文件同级目录,就会自动被识别。这样程序运行时就不会因为找不到文件报错了。运行结束的时候再吧这些解压出来的文件删除就好。

结构

│  ffmpeg_parsing.go     # 具体实现
│  parsing.go            # 接口定义
│
└─ffmpeg                 # 打包代码
    │  init_darwin.go    # mac打包代码
    │  init_linux.go     # linux打包代码
    │  init_windows.go   # windows打包代码
    │  readme.md
    │
    └─bin                # 二进制文件(从官网下载)
        ├─darwin         # mac版本
        │      ffmpeg
        │      ffplay
        │      ffprobe
        │      ffserver
        │
        └─windows        # windows版本
                ffmpeg.exe
                ffplay.exe
                ffprobe.exe

代码片段

parsing.go 

package mediaparsing

// IParsing 解析音频、视频、图片 获取分辨率时长等信息
type IParsing interface {
	// Info 获取媒体信息
	Info() (info MediaInfo, err error)
}

type MediaInfo struct {
	Height   int
	Width    int
	Duration float64 // 秒
}

 init_windows.go

//go:build windows

package ffmpeg

import (
	"embed"
	"io"
	"os"
)

//go:embed bin/windows
var Bin embed.FS

// InitFfmpegExecuteFile 初始化ffmpeg需要的二进制文件
func InitFfmpegExecuteFile() (err error) {
	err = copyFSFile("bin/windows/ffmpeg.exe", "ffmpeg.exe")
	if err != nil {
		return err
	}
	err = copyFSFile("bin/windows/ffplay.exe", "ffplay.exe")
	if err != nil {
		return err
	}
	err = copyFSFile("bin/windows/ffprobe.exe", "ffprobe.exe")
	return err
}

// DeleteFfmpegExecuteFile 删除ffmpeg二进制文件
func DeleteFfmpegExecuteFile() {
	_ = os.Remove("ffmpeg.exe")
	_ = os.Remove("ffplay.exe")
	_ = os.Remove("ffprobe.exe")
}

// copyFSFile 把fs文件复制到本地
func copyFSFile(FSFilePath, localPath string) error {
	ffmpegOpen, err := Bin.Open(FSFilePath)
	if err != nil {
		return err
	}
	defer ffmpegOpen.Close()
	ffmpegOut, err := os.Create(localPath)
	if err != nil {
		return err
	}
	defer ffmpegOut.Close()
	_, err = io.Copy(ffmpegOut, ffmpegOpen)
	return err
}

总结

这里只是给出一个比较取巧的解决方案,普通部署的时候基本用不到,如果用docker打包的话在基础镜像安装好ffmpeg就完美解决了。

不过倒是让我了解不是经常用到的embed和go的条件编译。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值