2023-03-27:avio_list_dir.c 是 FFmpeg 库自带的一个示例程序,它提供了列出目录中所有文件和子目录的功能,请用go语言改写。
答案2023-03-27:
这段代码实现了通过 AVIOContext 列出指定目录下的文件和子目录,并打印出它们的名称、大小、类型、权限等信息。
具体流程如下:
1.设置 FFmpeg 库的路径,以及调用 AvformatNetworkInit() 初始化网络相关的组件。
2.调用 AvioOpenDir() 打开指定目录,获取 AVIODirContext 对象。
3.循环调用 AVIODirContext.AvioReadDir() 方法读取目录下的文件和子目录,每次读取到一个目录项后,输出该目录项的信息。如果已经读取完所有目录项,则退出循环。
4.输出格式化的目录项信息,包括类型、大小、名称、权限等。
5.在每次循环中需要调用 AVIODirContext.AvioFreeDirectoryEntry() 方法释放当前目录项所占用的内存空间。
6.最后调用 AvioCloseDir() 关闭目录并销毁 AVIODirContext 对象,调用 AvformatNetworkDeinit() 释放网络相关的资源。
需要注意的是,这段代码只能在支持 AVIOContext 的平台上运行,例如 Linux 上的文件系统或者 S3、HDFS 等云存储服务。而 Windows 平台上不支持 AVIOContext,因此无法使用该方法列出目录下的文件和子目录。
代码见github/moonfdd/ffmpeg-go。
执行命令:
代码语言:javascript复制go run ./examples/internalexamples/avio_list_dir/main.go .
golang代码如下:
代码语言:javascript复制package main
import (
"fmt"
"os"
"github.com/moonfdd/ffmpeg-go/ffcommon"
"github.com/moonfdd/ffmpeg-go/libavformat"
"github.com/moonfdd/ffmpeg-go/libavutil"
)
func main() {
os.Setenv("Path", os.Getenv("Path") ";./lib")
ffcommon.SetAvutilPath("./lib/avutil-56.dll")
ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")
ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")
ffcommon.SetAvformatPath("./lib/avformat-58.dll")
ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
ffcommon.SetAvswscalePath("./lib/swscale-5.dll")
genDir := "./out"
_, err := os.Stat(genDir)
if err != nil {
if os.IsNotExist(err) {
os.Mkdir(genDir, 0777) // Everyone can read write and execute
}
}
main0()
}
func main0() (ret ffcommon.FInt) {
libavutil.AvLogSetLevel(libavutil.AV_LOG_DEBUG)
if len(os.Args) < 2 {
usage(os.Args[0])
ret = 1
return
}
libavformat.AvformatNetworkInit()
ret = list_op(os.Args[1])
libavformat.AvformatNetworkDeinit()
if ret < 0 {
ret = 1
}
return
}
func type_string(type0 int32) string {
switch type0 {
case libavformat.AVIO_ENTRY_DIRECTORY:
return "<DIR>"
case libavformat.AVIO_ENTRY_FILE:
return "<FILE>"
case libavformat.AVIO_ENTRY_BLOCK_DEVICE:
return "<BLOCK DEVICE>"
case libavformat.AVIO_ENTRY_CHARACTER_DEVICE:
return "<CHARACTER DEVICE>"
case libavformat.AVIO_ENTRY_NAMED_PIPE:
return "<PIPE>"
case libavformat.AVIO_ENTRY_SYMBOLIC_LINK:
return "<LINK>"
case libavformat.AVIO_ENTRY_SOCKET:
return "<SOCKET>"
case libavformat.AVIO_ENTRY_SERVER:
return "<SERVER>"
case libavformat.AVIO_ENTRY_SHARE:
return "<SHARE>"
case libavformat.AVIO_ENTRY_WORKGROUP:
return "<WORKGROUP>"
case libavformat.AVIO_ENTRY_UNKNOWN:
default:
break
}
return "<UNKNOWN>"
}
func list_op(input_dir string) (ret int32) {
var entry *libavformat.AVIODirEntry
var ctx *libavformat.AVIODirContext
var cnt int32
var filemode [4]byte
var uid_and_gid [20]byte
//注意Windows下会返回-40,也就是Function not implement,方法未实现,也就是说windows下不支持此方法
ret = libavformat.AvioOpenDir(&ctx, input_dir, nil)
defer libavformat.AvioCloseDir(&ctx)
if ret < 0 {
libavutil.AvLog(uintptr(0), libavutil.AV_LOG_ERROR, "Cannot open directory: %s.n", libavutil.AvErr2str(ret))
return
}
cnt = 0
for {
ret = ctx.AvioReadDir(&entry)
if ret < 0 {
libavutil.AvLog(uintptr(0), libavutil.AV_LOG_ERROR, "Cannot list directory: %s.n", libavutil.AvErr2str(ret))
return
}
if entry == nil {
break
}
if entry.Filemode == -1 {
filemode[0] = '?'
filemode[1] = '?'
filemode[2] = '?'
} else {
f := fmt.Sprint(entry.Filemode)
if len(f) >= 1 {
filemode[0] = f[0]
}
if len(f) >= 2 {
filemode[1] = f[1]
}
if len(f) >= 3 {
filemode[2] = f[2]
}
}
u := fmt.Sprintf("%d%d", entry.UserId, entry.GroupId)
copy(uid_and_gid[0:19], []byte(u))
if cnt == 0 {
libavutil.AvLog(uintptr(0), libavutil.AV_LOG_INFO, "%-9s s 0s s %s s s sn",
"TYPE", "SIZE", "NAME", "UID(GID)", "UGO", "MODIFIED",
"ACCESSED", "STATUS_CHANGED")
}
libavutil.AvLog(uintptr(0), libavutil.AV_LOG_INFO, "%-9s s 0s s %s s s sn",
type_string(entry.Type),
fmt.Sprint(entry.Size),
ffcommon.StringFromPtr(entry.Name),
string(uid_and_gid[:]),
fmt.Sprint(filemode),
fmt.Sprint(entry.ModificationTimestamp),
fmt.Sprint(entry.AccessTimestamp),
fmt.Sprint(entry.StatusChangeTimestamp))
libavformat.AvioFreeDirectoryEntry(&entry)
cnt
}
return
}
func usage(program_name string) {
fmt.Printf("usage: %s input_dirnAPI example program to show how to list files in directory accessed through AVIOContext.n", program_name)
}