osnosn

  博客园 :: 首页 :: 博问 :: 闪存 :: :: 联系 :: 订阅 订阅 :: 管理 ::

golang_操作HDF5文件_gonum/hdf5_linux_libhdf5-dev_遍历文件结构

转载注明来源: 本文链接 来自osnosn的博客,写于 2022-01-22.

参考

笔记

  • Debian-11 需要 apt install libhdf5-dev (安装成功。是 hdf5-1.10.6)
  • CentOS-8 需要 yum install hdf5-devel (需要epel)
    • 如果提示:安装失败,包冲突。启用 yum config-manager --enable powertools,就可以安装了。
      版本较低, 是 hdf5-1.10.5
  • 另一个选择,去下载源码包 然后
    ./configure --prefix=/usr/local/hdf5
    make
    make check
    make install
    通过源码安装。可以安装最新的。
  • 参考 【gonum/hdf5/cmd】中的例子。

遍历hdf5结构 (不能遍历属性)

//filename: read_hdf5.go

package main

import (
        "flag"
        "fmt"
        "gonum.org/v1/hdf5"
)

func main() {
        hdf5_filename := "" //命令行参数,hdf5文件名
        flag.StringVar(&hdf5_filename, "f", "", "hdf5 filename")
        flag.Parse()

        if len(hdf5_filename) < 2 {
                fmt.Printf("hdf5 file missing!\n")
                return
        }

        fmt.Println()
        //版本号
        version, err := hdf5.LibVersion()
        if err != nil {
                fmt.Printf("** error ** %s\n", err)
                return
        }
        fmt.Printf("=== version: %s ===\n", version)
        // check hdf5 file
        if !hdf5.IsHDF5(hdf5_filename) {
                fmt.Printf("\"%s\" Not a hdf5 file!\n", hdf5_filename)
                return
        }
        // open hdf5 file
        ff, err := hdf5.OpenFile(hdf5_filename, hdf5.F_ACC_RDONLY)
        if err != nil {
                panic(err)
        }
        fmt.Printf("=== hdf5 opened.\n")

        //显示hdf5 结构, 仅支持 group,dataset 两种
        prefix := " " //至少一个空格
        Show_h5(prefix, &ff.CommonFG)

        fmt.Printf("=== close hdf5.\n")
        ff.Close()
}

func Show_h5(prefix string, obj *hdf5.CommonFG) {
        //显示当前节点的 名称,类型
        fmt.Printf("%s(%s) %s \n", prefix, obj.Type(), obj.Name())
        //获取当前节点中包含的,下级节点数目
        ObjNum, _ := obj.NumObjects()
        if ObjNum < 1 {
                return
        }
        prefix = prefix[:len(prefix)-1] + " |-" //前缀,缩进一层
        for ii := uint(0); ii < ObjNum; ii++ {
                ObjName, _ := obj.ObjectNameByIndex(ii) //节点name
                ObjType, _ := obj.ObjectTypeByIndex(ii) //节点type
                if ObjType == hdf5.H5G_GROUP { //是GROUP
                   //fmt.Printf("%s(%s) %s \n", prefix, ObjType, ObjName)
                        obj, _ := obj.OpenGroup(ObjName)
                        Show_h5(prefix, &obj.CommonFG) //递归调用
                        obj.Close()
                } else if ObjType == hdf5.H5G_DATASET { //是DATASET
                   fmt.Printf("%s(%s) %s \n", prefix, ObjType, ObjName)
                }
        }

}
  • 编译,执行
    go build read_hdf5.go
    ./read_hdf5 -f xxxx.hdf5
  • 无法遍历 属性
    • hdf5 group 官网
      • Documentation->HDF5->HDF5 Examples ->【Examples in the Source Code】的例子 【h5_attribute.c】 中,给出了在 C++ 中遍历属性的方法。用到了H5Oget_info3()H5Aiterate2()
      • Documentation->HDF5->HDF5 User Guides->HDF5 User's Guide也写了。
    • 可是 gonum/hdf5 并没有封装这两个函数(2022-01)。
  • 属性,无法获取它的 Datatype,应该是没封装这个功能(2022-01)。

读取hdf5的dataset中的属性

// 或者 obj = & hdf5_fd.CommonFG  // hdf5_fd = hdf5.OpenFile( ... )
// 或者 obj = & group.CommonFG    // group = xxx.OpenGroup( ... )

 dset, _ := obj.OpenDataset("mydataset")
 attName := "Description"  //字符串类型的属性
 att, err := dset.OpenAttribute(attName)
 if err == nil {
    var buf string
    att.Read(&buf, hdf5.T_GO_STRING)
    buflen := len(buf)
    fmt.Printf(" %s=%s (%d)\n", attName,  buf, buflen)
    att.Close()
 }
 attName = "Rate"        //float32 类型的属性
 att, err = dset.OpenAttribute(attName)
 if err == nil {
    var rate float32
    att.Read(&rate, hdf5.T_NATIVE_FLOAT)
    fmt.Printf(" %s=%.3f \n", attName,  rate)
    att.Close()
 }
 dset.Close()
  • 属性,无法获取它的 Datatype,应该是没封装这个功能(2022-01)。
  • 指定 float32 属性的读取,没问题。
  • 指定 string 属性的读取。有的读取正常,有的会多读出几个字节的乱码。我也无法解决。估计是 gonum/hdf5 封装的问题。
    用系统自带的hdf5-tools(C写的工具),读取string的属性,很正常。
    • 系统debian-11, 装的是hdf5-1.10.6 , gonum/hdf5 是最新的包(2022-01)。
  • 无法获取单条记录的总大小,itemsize。(2022-01)
  • 读取数据可以用 []byte 做 buffer,用 encoding/binary 包,LittleEndian 解析。
  • 总之,gonum/hdf5 远未完成。没法使用。(2022-01)

静态编译

  • CGO_ENABLED=1 go build -v -ldflags '-w -s -extldflags "-static -lhdf5 -lhdf5_hl -lhdf5_serial -lhdf5_serial_hl -lm -ldl -lz -lsz -laec"' xxx.go
    会有个warning,说 hdf5 用了 dl 库的 dlopen,会在运行中加载 glibc 动态库。
    所以,静态编译的程序,需要在有相同 glibc 的系统中。
    • 我测试,debian中编译的,在centos中运行会有问题,只要操作hdf5文件,就会出错退出
      但可以在别的,没装hdf5库的debian中运行,操作hdf5文件。

使用一个hdf5的旧库

  • github.com/sbinet/go-hdf5
    package main
    
    import (
            "fmt"
            "github.com/sbinet/go-hdf5"
    )
    
    func main() {
            fmt.Println("=== go-hdf5 ===")
            version, err := hdf5.LibVersion()
            if err != nil {
                    fmt.Printf("** error ** %s\n", err)
                    return
            }
            fmt.Printf("=== version: %s", version)
            fmt.Println("=== bye.")
    }
    
  • go build 出错,显示h5t_shim.go:259:5: constant 18446744073709551615 overflows int64
    原因是H5Tpublic.h中定义的H5T_VARIABLE类型是size_t实际是long unsigned int(C语言),
    而go-hdf5中定义的类型是 int64(golang),对应是long signed long(C语言)。

去官网搜索一下hdf5库

  • https://pkg.go.dev/ 搜索 hdf5,发现有好几个。没有一个可以用。

转载注明来源: 本文链接 https://www.cnblogs.com/osnosn/p/15834309.html
来自 osnosn的博客 https://www.cnblogs.com/osnosn/ .


posted on 2022-01-22 16:18  osnosn  阅读(562)  评论(0编辑  收藏  举报