区块链开发之Go语言—IO操作

简介:

本篇文章是对区块链开发中的Go语言中常用的io操作的库做一个梳理

io,最基本的io

Reader

type Reader interface {
    Read(p []byte) (n int, err error)
}

实现了Reader接口的都可以用read方法,将数据读入到p字节数组,n表示读取了几个字节,err返回错误。 如果读到了文件尾EOF,则err返回EOF。
注意,当文件最后一小段已经无法填满p这个字节数组时,不会产生EOF的错误,只会在下一次读取时产生n=0,err=io.EOF的错误

举例

func main() {
    file, _ := os.Open("main.go")
    var a [128]byte

    count:=0
    for {
        n, err := file.Read(a[:])
        count+=1
        if err != nil {
            if err == io.EOF {
                break
            } else {
                os.Exit(1)
            }
        }
        fmt.Printf("%s\n", a[:n])
    }
    fmt.Printf("%d\n", count)

}

Writer

type Writer interface {
    Write(p []byte) (n int, err error)
}

Write 将 len(p) 个字节从 p 中写入到基本数据流中。它返回从 p 中被写入的字节数 n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误。若 Write 返回的 n < len(p),它就必须返回一个 非nil 的错误。
常见错误原因有磁盘满了

ReaderAt 和 WriterAt 接口

和Reader,Writer类似,但是需要自己调控偏移量。
注意:接近文件尾巴时,当n小于数组大小时也触发了err.EOF,需要自行把最后n小于数组大小的这点数据处理一下。

举例:

func main() {
    file, _ := os.Open("main.go")
    var a [128]byte

    count := 0
    var pos int64 = 0
    for {
        n, err := file.ReadAt(a[:], pos)
        count += 1
        pos += int64(n)
        if err != nil {
            if err == io.EOF {
                fmt.Printf("%s", a[:n]) //区别在这里
                break
            } else {
                os.Exit(1)
            }
        }
        fmt.Printf("%s", a[:n])
    }
    fmt.Println()
    fmt.Printf("%d", count)

}

ReaderFrom 和 WriterTo 接口

一次性读完直到EOF,或者写入全部数据

Seeker 接口

type Seeker interface {
    Seek(offset int64, whence int) (ret int64, err error)
}

用来设置偏移量,也就是从哪开始读,offset由whence解释。

  • 0 表示相对于文件的起始处
  • 1 表示相对于当前的偏移,
  • 2 表示相对于其结尾处。

ByteReader 和 ByteWriter

读或写一个字节

ioutil — 方便的IO操作函数集

ReadAll

一次性读取数据

ReadDir

读取目录并返回排好序的文件和子目录名

ReadFile 和 WriteFile

func WriteFile(filename string, data []byte, perm os.FileMode) error

这里特别注意的是写文件的权限问题,perm的数值,和linux规则一致 四位(777):

模式

数字

rwx

7

rw-

6

r-x

5

r--

4

-wx

3

-w-

2

--x

1

---

0

组合如0666,表示rw-rw-rw-

bufio,带缓存的io

是io库的包装,提供带缓存的方法

ReadSlice、ReadBytes、ReadString 和 ReadLine 方法

后三个方法最终都是调用ReadSlice来实现的

ReadSlice
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)

示例:

reader := bufio.NewReader(strings.NewReader("http://studygolang.com. \nIt is the home of gophers"))
line, _ := reader.ReadSlice('\n')
fmt.Printf("the line:%s\n", line)
// 这里可以换上任意的 bufio 的 Read/Write 操作
n, _ := reader.ReadSlice('\n')
fmt.Printf("the line:%s\n", line)
fmt.Println(string(n))

输出:

the line:http://studygolang.com. 

the line:It is the home of gophers
It is the home of gophers

注意ReadSlice每次返回的line是指向同一个缓存数组,因此ReadSlice的实现是反复覆盖重写缓存数组。

如果ReadSlice在找到分界符前

  1. 缓存数组就满了,则返回bufio.ErrBufferFull
  2. 遇到EOF了,则返回ErrEOF
ReadBytes
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)

返回的byte是copy的一份数组

从以下实验可看出来

reader := bufio.NewReader(strings.NewReader("http://studygolang.com. \nIt is the home of gophers"))
line, _ := reader.ReadBytes('\n')
fmt.Printf("the line:%s\n", line)
// 这里可以换上任意的 bufio 的 Read/Write 操作
n, _ := reader.ReadBytes('\n')
fmt.Printf("the line:%s\n", line)
fmt.Println(string(n))

输出

the line:http://studygolang.com. 

the line:http://studygolang.com. 

It is the home of gophers
ReadString

是对ReadBytes的封装,将返回的line转换成string

ReadLine
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)

这里要说的是isPrefix,用于读取的一行超过了缓存大小,则isPrefix为true,下次还读这行余下的部分,直到读完这行才isPrefix返回false

ReadLine返回的文本不会包含行结尾("\r\n"或者"\n")

Peek

该方法只是“窥探”一下Reader中没有读取的n个字节。好比栈数据结构中的取栈顶元素,但不出栈。

func (b *Reader) Peek(n int) ([]byte, error)

同上面介绍的ReadSlice一样,返回的[]byte只是buffer中的引用。所以在并发的时候有可能就被别人给改了

Scanner 类型和方法

用于方便的按token读取数据,token的分词规则用SplitFunc定义。默认按行分词,会去掉末尾换行符。 了解Scanner前要先了解SplitFunc

SplitFunc
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

SplitFunc 定义了 用于对输入进行分词的 split 函数的签名。

参数

  1. data 是还未处理的数据,
  2. atEOF 标识 Reader是否还有更多数据(是否到了EOF)。

返回值

  1. advance data里下一个token开始位置
  2. token 表示当前token的结果数据
  3. err 则代表可能的错误。

举例

func main() {
    // Comma-separated list; last entry is empty.
    const input = "1,2,3,4,"
    scanner := bufio.NewScanner(strings.NewReader(input))
    // Define a split function that separates on commas.
    onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
        for i := 0; i < len(data); i++ {
            if data[i] == ',' {
                return i + 1, data[:i], nil
            }
        }
        // There is one final token to be delivered, which may be the empty string.
        // Returning bufio.ErrFinalToken here tells Scan there are no more tokens after this
        // but does not trigger an error to be returned from Scan itself.
        return 0, data, bufio.ErrFinalToken
    }
    scanner.Split(onComma)
    // Scan.
    for scanner.Scan() {
        fmt.Printf("%q ", scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading input:", err)
    }
}

输出

"1" "2" "3" "4" "5"

你也可以用系统定义好的几个分割token的方法。


  1. ScanBytes 返回单个字节作为一个 token。


  2. ScanRunes 返回单个 UTF-8 编码的 rune 作为一个 token。返回的 rune 序列(token)和 range string类型 返回的序列是等价的,也就是说,对于无效的 UTF-8 编码会解释为 U+FFFD = "\xef\xbf\xbd"。


  3. ScanWords 返回通过“空格”分词的单词。如:study golang,调用会返回study。注意,这里的“空格”是 unicode.IsSpace(),即包括:'\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP)。


  4. ScanLines 返回一行文本,不包括行尾的换行符。这里的换行包括了Windows下的"\r\n"和Unix下的"\n"。

Scanner 的使用方法
  1. NewScanner
  2. Split设置分割token的方法
  3. 循环scanner.Scan()
  4. 在循环里用scanner.Text()取token 示例
const input = "This is The Golang Standard Library.\nWelcome you!"
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
count := 0
for scanner.Scan() {
    count++
}
if err := scanner.Err(); err != nil {
    fmt.Fprintln(os.Stderr, "reading input:", err)
}
fmt.Println(count)

Writer

带缓存的writer,记得在最终的写入操作执行完后flush一下,确保全部缓存都真正写入。

参考

1.《Go语言标准库》The Golang Standard Library by Example



原文发布时间为:2018-03-12
本文作者:linxinzhe
本文来源:腾讯云 云+社区,如需转载请联系原作者。

目录
相关文章
|
5月前
|
SQL 关系型数据库 MySQL
go 通过sql操作mysql
go 通过sql操作mysql
30 1
|
1月前
|
传感器 安全 物联网
新技术趋势与应用随着科技的不断进步,新兴技术如区块链、物联网和虚拟现实等正迅速改变我们的世界。这些技术不仅在各自领域内展现出强大的潜力,还在相互融合中催生出更多创新应用场景。本文将探讨这些新兴技术的发展趋势及其在各行业中的应用前景,通过通俗易懂的语言和清晰的条理,带领读者了解其内涵和意义。
本文旨在探讨区块链技术、物联网和虚拟现实等新兴技术的发展趋势及其在各个行业的应用场景。通过分析这些技术的独特优势和潜在缺陷,揭示它们对未来社会和经济可能带来的深远影响。同时,结合实际案例,展示这些技术如何解决现实问题,为各行各业提供新的发展机遇。
59 4
|
5月前
|
监控 Go
go语言并发实战——日志收集系统(八) go语言操作etcd以及利用watch实现对键值的监控
go语言并发实战——日志收集系统(八) go语言操作etcd以及利用watch实现对键值的监控
go语言并发实战——日志收集系统(八) go语言操作etcd以及利用watch实现对键值的监控
|
5月前
|
安全 算法 定位技术
[Solidity][区块链安全入门]Solidity语言关于密码学知识的运用以及存在漏洞
密码学在区块链中扮演关键角色,确保机密性、完整性、身份认证和不可否认性。对称密钥加密用于快速加密,但不支持不可否认性。非对称加密(如RSA)解决了这一问题,每个用户拥有公钥和私钥。散列函数(如SHA-1、SHA-2)用于数字签名,保证信息来源和完整性。同态加密允许在不解密情况下处理加密数据,增强隐私保护。零知识证明则能验证信息正确性而不泄露额外信息,如ZCash使用该技术隐藏交易详情。环签名技术(如在门罗币中)隐藏签名者身份。区块链隐私保护措施包括混币技术,旨在混淆交易路径。网络和应用层面上也存在隐私挑战,需要综合策略来防御。
|
4月前
|
分布式计算 大数据 Go
MaxCompute操作报错合集之使用go sdk调用GetTunnelEndpoint出现报错:InvalidAction.NotFoundSpecified api is not found,该如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
4月前
|
运维 Devops API
阿里云云效操作报错合集之直接用API调用可以使用,但是本地用Go代码调用失败,是什么导致的?
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
5月前
|
关系型数据库 MySQL Go
Go语言介绍以及如何在Go语言中操作MySQL数据库
Go语言介绍以及如何在Go语言中操作MySQL数据库
58 3
|
5月前
|
运维 前端开发 Unix
用Go实现Ping操作
**摘要:** 本文介绍了 Ping 操作的原理和用途,并展示了如何用 Go 语言实现一个简单的 Ping 工具。Ping 是一个用于测试网络连接可达性和测量往返时间(RTT)的工具,常用于网络故障排查和监测网络稳定性。文中详细讲解了 ICMP 报文的结构,以及如何构建和发送 ICMP 请求报文,包括设置类型、代码、校验和、ID 和序列号等。通过示例代码,演示了如何编写 Go 代码实现 Ping 功能,包括计算校验和、设置超时、发送和接收数据包等步骤。
|
5月前
|
NoSQL 安全 Go
Go 语言 mongox 库:简化操作、安全、高效、可扩展、BSON 构建
go mongox 是一个基于泛型的库,扩展了 MongoDB 的官方库。通过泛型技术,它实现了结构体与 MongoDB 集合的绑定,旨在提供类型安全和简化的数据操作。 go mongox 还引入链式调用,让文档操作更流畅,并且提供了丰富的 BSON 构建器和内置函数,简化了 BSON 数据的构建。 此外,它还支持插件化编程和内置多种钩子函数,为数据库操作前后的自定义逻辑提供灵活性,增强了应用的可扩展性和可维护性。
93 6
|
5月前
|
存储 NoSQL Go
轻松上手,使用Go语言操作Redis数据库
轻松上手,使用Go语言操作Redis数据库