Go与Hdf5,数据读写实践

前言 HDF5 (Hierarchical Data Format) 是由美国伊利诺伊大学厄巴纳-香槟分校,是一种跨平台传输的文件格式,存储图像和数据 优势 通用数据模型,可以通过无限多种数据类型表示非常复杂、异构的数据对象和各种各样的元数据 高速原始数据采集 可移植和可扩展,文件大小没有限制 自描述的,不需要外部信息应用程序来解释文件的结构和内容 拥有用于管理、操作、查看和分析数据的开源工具和应用程序软件生态系统 在各种计算平台和编程语言(包括C、C++、Fortran90和Java)上运行的软件库。 参考文章链接: 大数据存储 hdf5简介 实践 环境安装 对于go语言,hdf5已经有了支持的库: gonum/hdf5,我们可以直接安装这个包,并且使用。 需要注意的是,这个包使用了 cgo,依赖了hdf5的C语言库,因此,需要我们自己预先安装,使用centos系统,可以很方便安装,直接使用命令: yum install -y hdf5 hdf5-devel 当然,如果系统没有软件源的话,hdf5也提供了源码安装,下载 hdf5-1.12.1,解压后,执行安装: cd hdf5-1.12.1 ./configure --prefix /usr/local make -j 2 && make install 然后我们初始化一个项目,名为 h5,用于编写go、hdf5 的简单测试用例 mkdir -p ~/go/src/h5 cd ~/go/src/h5 go mod init # 安装 go get -v gonum.org/v1/hdf5 使用 创建文件 func main() { // 创建hdf5文件 f, err := hdf5.CreateFile("data.h5", hdf5.F_ACC_TRUNC) if err != nil { panic(fmt.Errorf("failed to create hdf5 file: %e", err)) } defer f.Close() fmt.Println("File created.") } 创建文件的代码就一行: hdf5.CreateFile("data.h5", hdf5.F_ACC_TRUNC),其中 data.h5 为文件的名称,使用flag为hdf5.F_ACC_TRUNC,如果文件已存在的话,会清除原始文件里面的内容。 ...

<span title='2022-04-23 22:10:10 +0800 +0800'>April 23, 2022</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;LingZihuan

go: 读取文件

学习网站: https://gobyexample.com/reading-files 可以直接读取文件里面的所有内容到内存里面: data, err := os.ReadFile("/tmp/data") fmt.Println(string(data)) 有时候想要自定义一些操作,比如读取文件里面的某些内容,从某个位置开始读取等,这时候,我们可以用 os.Open 打开一个文件,返回一个 os.File 对象。 f, err := os.Open("/tmp/data") 我们可以定义一个缓存(5个字节的[]byte类型),然后从文件中读取内容,读取的内容大小上限为5: b1 := make([]byte, 5) n1, err := f.Read(b1) fmt.Printf("%d bytes read from file: %s\n", n1, string(b1)) 调用 f.Read来读取文件,返回两个结果,第一个为实际读取的内容长度,第二个为error。我们定义了一个长度为5的 b1 来存储文件内容,但是文件里面的内容长度可能只有3,因此,n1不一定等于5,它是实际读取的长度。 同样,我们还能用 os.Seek,来查找文件的位置,第一个参数为 offset,意味着偏移量,第二个参数为 whence, 0表示从文件的开始位置进行偏移查找 1表示从文件的当前位置开始偏移,如果之前已经设置过偏移,再次设置则从当前位置开始偏移 2表示从文件的末尾开始偏移 o2, err := f.Seek(6, 0) b2 := make([]byte, 2) n2, err := f.Read(b2) fmt.Printf("%d bytes read at %d\n", n2, o2) fmt.Printf("Value is : %s\n", string(b2[:n2])) golang 的 io包提供了一些有用的函数,帮助我们高效读取。比如 io.ReadAtLeast,可以更健壮地实现上的读取操作: o3, err := f.Seek(6, 0) b3 := make([]byte, 2) n3, err := io.ReadAtLeast(f, b3, 2) fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3)) 如果想要将文件指针倒回到最初的位置,没有内置的函数,但是使用 f.Seek(0, 0) 可以实现同样的效果: _, err := f.Seek(0, 0) golang的 bufio 包提供了 缓冲读取器,它提供和额外的读取方法,对于少量的读取很有用: r4 := bufio.NewReader(f) b4, err := r4.Peek(5) fmt.Printf("5 bytes: %s\n", string(b4)) 最后,我们应该在结束的时候关闭文件: ...

<span title='2022-04-18 00:05:28 +0800 +0800'>April 18, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan

go: grpc和protobuf

gRPC 一个高性能、开源的通用RPC框架。 gPPC是一个现代的开源高性能的远程过程调用框架,并且可以运行在任何环境中。它可以有效地连接数据中心内和跨数据中心的服务,支持负载均衡、跟踪、健康检查和身份验证。它也适用于分布式计算的最后一英里,将设备、移动应用程序和浏览器连接到后端服务。 gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services. github 地址: https://github.com/grpc/grpc 原来是用 C++ 写的,后来也有了go语言版本:https://github.com/grpc/grpc-go gRPC 和 go gPPC支持多个语言和平台,包括GO、Python、C++、Nodejs等,我们接下来学习的是使用go来体验一下gRPC的功能。 ...

<span title='2022-04-16 22:34:33 +0800 +0800'>April 16, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan

go 和 protobuf

Google protocol buffers 简称protobuf,它是谷歌提供的跨语言,跨平台的,可扩展的用来将结构化的数据进行序列化的一种机制。就像XML,但是更加精简、快速和简单。我们可以先预先定义我们的协议(写到一个 .proto 文件里面),里面声明了我们需要怎么去将数据结构化,然后,我们可以使用这份proto,去生成我们指定的语言源代码文件,我们就能够很方便地从各种数据流中读取结构化数据,或者是写入结构化数据。并且是跨语言的。 Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. 安装protoc编译器 .proto文件只是我们定义的协议文件,一般来讲,编程语言是不能直接使用这份文件的(除非是自己针对proto写一个自定义的解析逻辑,但是没人会这么闲),我们想要的,应该是简单高效的开发,可以即写即用那种。 因此,我们使用特定的编程语言编写服务时,需要将我们定义的 .proto 文件翻译(编译)成为对应的语言文件,这时,google 给我们提供了 protoc。 ...

<span title='2022-04-14 21:14:52 +0800 +0800'>April 14, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan

Go 使用mongodb

安装 mkdir go-mongo go mod init go-mongo go get go.mongodb.org/mongo-driver/mongo 使用 数据库里面有一条这样的数据: { "_id": { "$oid": "6252912ec4495f97bccf41aa" }, "title": "My Mongo Post", "create_time": { "$date": "2022-04-10T10:33:45.149Z" }, "viewer": 201 } 连接数据库 // 关键代码 const MONGO_URI = "mongodb://localhost:27017/test" client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(MONGO_URI)) // 优雅关闭连接 defer client.Disconnect(context.TODO()) 数据查询 首先获取到对应的database以及collection coll := client.Database("test").Collection("post") 然后查询: coll := client.Database("test").Collection("post") var result bson.M // 需要一个bson.M 对象,用于存储查询回来的数据 // FindOne 接受2个参数,一个context,一个filter,filter 为 bson.D类型 err = coll.FindOne(context.TODO(), bson.D{}).Decode(&result) if err == mongo.ErrNoDocuments { fmt.Printf("No document found.\n") return } else if err != nil { panic(err) } fmt.Printf("Found document result: %s\n", result) 数据查询注意点: 需要一个 bson.M 对象,用于存储返回的数据 Collection.FindOne 接受3个参数,ctx、filter和opts,返回的是一个 SingleResult 对象 ctx可以为nil,如果为nil的话,默认会创建一个 context.Backgroud的context filter为查询条件,为 bson.D 类型,上面代码默认为空,意味着查询任意一条数据。也可以指定特定的条件,如 bson.d{{"title", "first post"}},意味着查询 tile 为 first post 的文档。 opts:类型为 options.FindOneOptions 类型,查询的额外条件,比如限定返回的具体字段:&options.FindOneOptions{Projection: map[string]int{"_id": 0}},这个options禁止返回_id字段。 使用 SingleResult.Decode方法将返回的SingleResult反序列化为 bson.M 对象,SingleResult.Decode(&result) 上述查询输出: ...

<span title='2022-04-10 16:06:40 +0800 +0800'>April 10, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;LingZihuan