4.10. 读取 File

未匹配的标注

Github: github.com/bigfile/bigfile

读取 File

读取 File 也即下载文件,稍微复杂,服务端流式响应,示例如下:

package main

import (
    "bytes"
    "context"
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io"
    "io/ioutil"
    "strconv"

    "github.com/bigfile/bigfile/internal/util"
    "github.com/bigfile/bigfile/rpc"
    "google.golang.org/grpc/metadata"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

func createConnection() (*grpc.ClientConn, error) {
    var (
        err           error
        conn          *grpc.ClientConn
        cert          tls.Certificate
        certPool      *x509.CertPool
        rootCertBytes []byte
    )
    // 加载客户端证书
    if cert, err = tls.LoadX509KeyPair("client.pem", "client.key"); err != nil {
        return nil, err
    }

    // 创建证书池
    certPool = x509.NewCertPool()
    if rootCertBytes, err = ioutil.ReadFile("ca.pem"); err != nil {
        return nil, err
    }

    if !certPool.AppendCertsFromPEM(rootCertBytes) {
        return nil, err
    }

    // 连接服务器
    if conn, err = grpc.Dial("192.168.0.103:10986", grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{cert},
        RootCAs:      certPool,
    }))); err != nil {
        return nil, err
    }
    return conn, err
}

func main() {
    var (
        err  error
        conn *grpc.ClientConn
    )

    if conn, err = createConnection(); err != nil {
        fmt.Println(err)
        return
    }
    defer conn.Close()

    var (
        client       = rpc.NewFileReadClient(conn)
        header       metadata.MD
        fileName     string
        fileHash     string
        dataHash     string
        dataBuffer   *bytes.Buffer
        fileSize     int
        streamClient rpc.FileRead_FileReadClient
    )

    // 创建流式客户端
    if streamClient, err = client.FileRead(context.Background(), &rpc.FileReadRequest{
        Token:   "ee3caab522b1848744c9df3aa980346f",
        FileUid: "b58a51fc0ee8d95918c9715bfdb2af0d",
    }); err != nil {
        fmt.Println(err)
        return
    }

    // 读取 Header,Header 存在文件大小, hash 值以及名称
    if header, err = streamClient.Header(); err != nil {
        fmt.Println(err)
        return
    }
    fileName = header.Get("name")[0]
    fileHash = header.Get("hash")[0]
    if fileSize, err = strconv.Atoi(header.Get("size")[0]); err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("name = %s, hash = %s, size = %d\n", fileName, fileHash, fileSize)
    dataBuffer = new(bytes.Buffer)

    // 持续读取文件
    for {
        if resp, err := streamClient.Recv(); err != nil {
            if err != io.EOF {
                fmt.Println(err)
                return
            }
            break
        } else {
            if _, err = dataBuffer.Write(resp.Content); err != nil {
                fmt.Println(err)
                return
            }
        }
    }

    // 验证 hash
    if dataHash, err = util.Sha256Hash2String(dataBuffer.Bytes()); err != nil {
        fmt.Println(err)
        return
    }
    if dataHash != fileHash {
        fmt.Println("file is broken")
        return
    }

    // 这里,您可以将内容保存到文件
    // _ = ioutil.WriteFile(fileName, dataBuffer.Bytes(), 0666)
}

这里我们也给出了下载文件的 示例,点击查看 FileReadRequest 以及 FileReadResponse 类型声明。

英文文档:bigfile.site

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
Michael001
讨论数量: 0
发起讨论 只看当前版本


暂无话题~