欢迎访问我的博客,你的支持,是我最大的动力!

Go语言学习笔记(7)-IO

Linux 小马奔腾 411℃ 评论
目录:
[显示]

I/O编程

输入/输出

相关的包
io,为IO原语提供基本接口,最重要的接口 Reader 和 Writer
io/iouitl,提供一些常用、方便的io操作函数
fmt,格式化io
bufio,带缓冲的io,提供缓冲的同时实现一些文本io功能

io 基本IO接口

io包为IO原语提供基本接口,不应假定它们对并行执行是安全的

1、Reader 接口

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

其是n是读入的字节数
接口的规则:
Read方法最多读取 len(p) 字节的数据,并保存到 p
读取的字节数 n 要满足 0<=n<=len(p)
当读取的字节数 n<len(p) 时,表示读取的数据不足以填满 p ,此时方法会立即返回,而不是等待更多的数据
读取过程中遇到错误,会返回读取的字节数 n 以及相应的错误 err
在底层输入流结束时 方法会返回 n>0 但是遇到错误可能会中断 EOF,也可以返回nil,此时再次调用Read方法,肯定会返回(0,EOF)
调用Read方法时 若 n>0 优先处理读入的数据,然后再处理错误 err, EOF也要这样处理
Read 方法不鼓励返回 n=0且err=nil的情况

注意,io.EOF 的定义是 var EOF = errors.New("EOF") 是一个error类型
在 n>0 且数据被读完的情况下,返回的 error 有可能是 EOF 也有可能是 nil

2、Writer 接口

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

接口规则:
Write方法向底层数据流写入 len(p) 字节的数据,这些数据来自切片p
返回被写入的字节数 n,其中 0<=n<=len(p)
若 n<len(p) 则必须返回一些非nil的err
若中途出现问题,也要返回非nil的err
Write方法绝对不参修改切片p以及其中的数据

func Println(a ...interface{})(n int, err error) {
return Fprintln(os.Stdout,a...)
}
fmt 格式化IO

1、Print 系列函数
包括:Fprint/Fprintf/Fprintln    Sprint/Sprintf/Sprintln     Prtint/Printf/Println
P函数会调用相应的F开头的函数,如
func Print(a ...interface{})(n int,err error){ return Fprint(os.Stdout, a...) }
F系函数第一个参数接收一个 io.Writer 类型,将内容输出到 io.Writer 中去

S系函数只是格式化内容为 string 类型,并不输出到某处,需要格式化字符串并返回时,可以使用

Sprint/Fprint/Print可以拼接字符串,不需要通过 strconv.Itoa() 转换
Sprintln/Fprintln/Println可以拼接字符串,但会以空格分隔

2、Stringer 接口

type Stringer interface {
Strings() string
}

转换成字符串

3、Formatter 接口

type Formatter interface {
Format(f State, c rune)
}

自定义输出格式(自定义占位符)。可调用Sprintf或Fprintf等函数生成其输出

fmt.State是一个接口,Format方法是被fmt包调用的,内部会实例化一个fmt.State接口的实例
实现了Formatter接口,相应的Stringer接口不起作用,但实现了Formatter接口的类型应该实现Stringer接口,这样方便在Format方法中调用String()方法

4、GoStringer 接口

type GoStringer interface {
GoString() string
}

定义类型的语法格式,用于打印格式化占位符为 %#v 的值
通常不需要实现该接口

5、Scan 系列函数
包括:Fscan/Fscanf/Fscanln   Sscan/Sscanf/Scanln   Scan/Scanf/Scanln
Scan系会调用Fscan系,如
func Scan(a ...interface{})(n int, err error){ return Fscan(os.Stdin, a...) }
Scan系从标准输入获取内空;Sscan系直接从字符串中获取内容
通常使用Scan/Scanf/Scanln这组函数,从标准输入获取

Scan/FScan/Sscan
将连续由空格分隔(空格可为\r、\n或\r\n)的值存储为连接的实参
若由空格分隔的段比实参个数多,忽略多出的部分

Scanf/Fscanf/Sscanf
将连续由空格分隔的值存储为连续的实参,其格式由 format 决定,换行符处停止扫描

Scanln/Fscanln/Sscanln
将连续由空格分隔的值存储为连续的实参,换行符处停止扫描

文本处理

strings,字符串操作,一般的字符串操作
vbytes,byte slice便利操作
strconv,字符串与基本数据类型之间的转换
regexp,正则表达式
unicode,Unicode编码、UTF-8/16编码

文件系统

os包提供了平台无关的操作系统功能接口,错误处理采用的是Unix风格的设计

os 系统功能实现

os包的接口实现在所有操作系统中都是一致的
对于某个系统特定的功能,需要使用 syscall 获取,syscall也是一个包
应优先使用os提供的功能,而不是syscall

path 兼容路径操作

path/filepath包涉及路径操作时,路径分隔使用 os.PathSeparator
path包能处理所有文件路径,不管什么系统
注意,路径操作函数不会校验路径是否真实存在

1、解析路径名字字符串
filepath.Dir()和filepath.Base()函数将路径名字符串分解成目录和文件名两部分
func Dir(path string) string
func Base(path string) string
func Ext(path string) string
filepath.Dir()返回该路径最后一个元素所有的目录
Dir("") -> .
Dir("/a") -> /
Dir("/a/") -> /a
Dir("/a/b.txt") -> /a
filepath.Base()返回路径的最后一个元素
Dir("") -> .
Dir("/a") -> a
Dir("/a/") -> a     #注意这种情况
Dir("/a/b.txt") -> b.txt
filepath.Ext()可获得路径中文件的扩展名,包含点"."
Ext(/a/b.txt) -> .txt

2、相对路径和绝对路径
filepath.IsAbs()函数可以判断返回的路径是否是绝对路径
func IsAbs(path string) bool
filepath.Abs()返回path代表的绝对路径,若path不是绝对路径,会加入当前工作目录使之成为绝对路径
func Abs(path string)(string, error)
因为存在硬链接,不保证返回的绝对路径是唯一指向该地址的绝对路径
os.Getwd出错时或路径名长度超过系统限制,Abs会返回错误
filepath.Rel()返回相对路径
func Rel(basepath,targpath string)(string, error)
filepath.Rel("/home/zuo/example", "/home/zuo/example/text/a.txt")) ->text/a.txt
filepath.Rel("/home/zuo/", "/text/a.txt")) ->../../text/a.txt

3、路径的切分和拼接
filepath.Split()得到路径和文件名,path==dir+file
func Split(path string)(dir, file string)
/ ->/ + ""
/a -> /+a   注意这种情况
/a/->/a/+""
filepath.Join()路径拼接,将任意数量的路径放到单一路径里,会根据需要添加路径分隔符
func Join(elem ...string) string
filepath.SplitList()用于分隔环境变量,返回切片类型
func SpitList(path string) []string

4、规整化路径
filepath.Clean()返回和path代表同一地址的最短路径
func Clean(path string) string
如将多个连接的路径分隔符替换为单个路径分隔符

5、文件路径匹配
filepath.Match()
func Match(pattern,name string)(matched bool, err error)
* 匹配0或多个非路径分隔符的字符
? 匹配1个非路径分隔符的字符
[] 字符范围
必须全匹配上,不只是子串,该函数很少使用
filepath.Glob()返回所有匹配了模式字符串pattern的文件列表或nil,Glob会忽略文件系统相关错误,只在pattern不合法时返回错误
func Glob(pattern string)(matches []string,err error)
Glob()常见用法是读取某个目录下所有文件,如
filepath.Glob("/root/*.txt")

6、遍历目录
filepath.Walk()遍历目录树,遍历root指定的目录下的文件树,对每一个该文件树中的目录和文件都会调用walkFn,包括root自身
所有访问目录、文件时遇到的错误都会传递给walkFn过滤
文件是按字典顺序遍历,这让输出更漂亮,但处理非常大的目录时效率会降低
func Walk(root string, walkFn WalkFunc) error
Walk不会遍历符号链接
type WalkFunc func(path string, info os.FileInfo, err error) error

unix分隔符是 / ,windows是 \
在使用path包时,应该总是使用 / 不论什么系统
path包提供的函数,filepath都有提供,功能类似,实现不同
一般应该使用filepath而不是path包

数据结构与算法

算法
math,实现数学函数计算
math/big,大整数的高精度计算
math/cmplx,复数基本函数操作
math/rand,伪随机数生成器

数据结构
sort,包含基本排序方法,支持切片数据排序以及用户自定义数据集合排序
index/suffixary,后缀数组相关算法以支持许多常见字符串操作
container,堆、链表、环

排序

四种基本排序算法:插入排序、归并排序、堆排序、快速排序,在sort包内实现
对数据集合排序时,不需要考虑用哪种排序方法,只需要实现 sort.Interface 定义的三个方法:
获取数据集合长度 Len() ,比较两个元素大小 Less(),交换两个元素位置 Swap() 即可对数据集合进行排序
sort 包会根据实现数据自动选择高效的排序算法

1、数据集合排序

type Interface interface {
Len() int
Less(i,j int) bool
Swap(i,j int)
}
func Sort(data Interface)  //排序函数
func IsSorted(data Interface) bool  //判断是否已排好序

默认是升度排序,要实现降序排序,可修改 Less() 函数
也可以使用 Reverse() 函数

func Reverse(data Interface) Interface

Search() 使用二分法查找
func Search(n int, f func(int) bool) int
常用于搜索元素 x 是否在已经升序排好的切片 s 中

2、切片排序
sort 原生支持[]int, []float64, []string 的排序操作,即不必自已实现Len() Less() Swap()
sort 定义了 IntSlice 类型,实现了 sort.Interface 接口

2.1、[]int 排序

2.2、[]float64 排序

实现与Ints类似
type Float64Slice []float64
func Float64s(a []float64)
func Float64sAreSorted(a []float64) bool
func SearchFloat64s(a []float64,x float64) int

2.3、[]string 排序

基于字典序排序
type StringSlice []string
func Strings(a []string)
func StringsAreSorted(a []string) bool
func SearchString(a []string,x string) int

container

container/heap 堆
container/list 链表
container/ring 环

container/heap 堆
堆使用的数据结构是最小二叉树,根节点比左子树和右子树的值都小

type Interface interface{
sort.Interface
Push(x interface{})  //添加一个元素x并返回Len()
Pop() interface{} //移除并返回元素长度Len()-1
}

堆继承自 sort.Interface 实现这 3+2 个方法,就实现了一个堆
堆的pop操作会弹出最小的元素

container/list 链表
链表是有prev和next指针的数组

type Element struct{
next,prev *Element
list *List
Value interface{}  //元素
}
type List struct {
root Element  //链表根元素
len int  //链表长度
}

list对应的方法:

container/ring 环

type Ring struct {
next,prev *Ring
Value interface{}
}

初始化环时,需要定义环的大小,然后对环的每个元素进行赋值
Do()方法能遍历一次环,对每个元素执行一个功能

ring 提供的方法:

 

转载请注明:轻风博客 » Go语言学习笔记(7)-IO

喜欢 (0)or分享 (0)