说明:这个专题,包含了Go语言中关于I/O操作涉及的包、方法、类型的全讲
1.bytes包:字节切片、Buffer和Reader
学习本部分之前,希望对Go语言新特性--切片有所了解。
Go语言标准库bytes包,提供了对字节切片进行读写操作的一系列函数和方法,主要包括三部分:1.数组切片([]byte)处理函数2.Buffer对象3.Reader对象。
1_1.字节切片处理函数
Go语言提供的字节切片处理函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。
1_1_1.字节切片基本处理函数
字节切片的基本处理函数主要有Contains(),Count(),Map(),Repeat(),Replace(),Rune()和Join()共七个函数,下面分别介绍。
(1)Contains()函数。Contains()函数的功能室检查字节切片b是否包含子切片subslice,如果包含返回true,否则返回false。该函数原型定义如下:
func Contains(b, subslice []byte) bool
例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("Golang") subslice1 := []byte("go") subslice2 := []byte("Go") fmt.Println(bytes.Contains(s, subslice1)) fmt.Println(bytes.Contains(s, subslice2)) }
该例测试结果为:
false true
(2)Count()函数。Count()函数的功能室计算子字节切片sep在字节切片s中非重叠示例的数量,该函数原型的定义如下:
func Count(s, sep []byte) int
例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("banana") sep1 := []byte("ban") sep2 := []byte("na") sep3 := []byte("a") fmt.Println(bytes.Count(s, sep1)) fmt.Println(bytes.Count(s, sep2)) fmt.Println(bytes.Count(s, sep3 )) }
该例测试结果是:
1 2 3
(3)Map()函数。Map()函数的功能是:首先把s转换为UTF-8编码的字节序列,然后使用mapping函数把s中的每个Unicode字符映射成对应的字符,最后将映射结果存放到一个新创建的字节切片,并返回此新字节切片。该函数原型定义如下:
func Map(mapping func(r rune) rune, s []byte) []byte
在函数Map()中参数mapping映射函数;参数s是被处理的字节切片。
例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("同学们,上午好!") m := func(r rune) rune { if r == '上' { r = '下' } return r } fmt.Println(string(s)) fmt.Println(string(bytes.Map(m, s))) }
该例的测试结果是:
同学们,上午好!
同学们,下午好!
(4)Repeat()函数。Repeat()函数的功能是把切片b复制count此组合成一个新的字节切片并返回。该函数原型定义如下:
func Repeat(b []byte, count int) []byte
在函数Repeat()中,参数b是被复制的字节切片;参数count是复制次数。
例如:
package main import ( "bytes" "fmt" ) func main() { b := []byte("na") count := 2 fmt.Println("ba" + string(bytes.Repeat(b, count))) }
该例测试结果是:
banana
Replace()函数。Replace()函数的功能是返回字节切片s的一个副本,并把前n个不重叠的子切片old替换为new;如果n<0则不限制替换的数量。该函数原型定义如下:
func Replace(s, old, new []byte, n int) []byte
在函数Replace()中,参数s是原字节切片;参数old是被替换的子切片;参数new是替换切片;参数n是替换次数。
例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("google") old := []byte("o") news := []byte("oo") n := 1 fmt.Println(string(bytes.Replace(s, old, news, n))) fmt.Println(string(bytes.Replace(s, old, news, -1))) }
该例测试结果为:
gooogle
goooogle
(6)Rune()函数。Rune()函数的功能是把s转换为UTF-8编码的字节序列,并返回对应的Unicode切片。该函数原型定义如下:
func Runes(s []byte) []rune
在函数Rune()中,参数s是需要被转换的字节切片。
例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("中华人名共和国") r := bytes.Runes(s) fmt.Printf("转换前字符串 %q长度: %d字节 ", string(s), len(s)) fmt.Printf("转换后字符串 %q长度: %d字节 ", string(r), len(r)) }
该例的测试结果为:
转换前字符串 "中华人名共和国"长度: 21字节
转换后字符串 "中华人名共和国"长度: 7字节
(7)Join()函数。Join()函数的功能是用字节切片sep把a中的每个字节切片连成一个字节切片并返回。该函数的原型定义如下:
func Join(s [][]byte, sep []byte) []byte
在函数Join()中,参数s是字节切片的切片;参数sep是用于连接的字节切片。
例如:
package main import ( "bytes" "fmt" ) func main() { s := [][]byte{[]byte("你好"), []byte("世界")} sep := []byte(",") fmt.Println(string(bytes.Join(s, sep))) }
该例的测试结果是:
你好,世界
1_1_2.字节切片比较函数
字节切片比较函数共有三个:Compare()、Equal()、EqualFold(),它们的作用和返回值都有所区别下面分别介绍。
(1)Compare()函数。Compare()函数的功能室根据字节的值比较字节切片a和b的大小。如果a=b,返回0,如果a>b,返回1,如果a< b返回-1.该函数原型定义如下:
func Compare(a, b []byte) int
在函数Compare()中,参数a b是需要比较两个字符切片。
(2)Equal()函数。Equal()函数的功能是比较两个字节切片是否相等,如果参数为nil,则等同于空的字节切片。如果a=b,则返回true;否则,返回false。该函数的定义如下:
func Equal(a, b []byte) bool
在函数Equal()中,参数a b是需要比较的连个字节切片。
(3)EqualFold()函数。EqualFold()函数的功能是把s和t转换成UTF-8字符串进行比较,并且忽略大小写。如果s=t,返回true;否则,返回false。该函数原型定义如下:
func EqualFold(s, t []byte) bool
在函数EqualFold()中,参数s t是需要比较的两个字节切片。
例如:
package main import ( "bytes" "fmt" ) func main() { a := []byte("abc") b := []byte("Abc") s := []byte("GOLANG") t := []byte("golang") fmt.Println(bytes.Compare(a, b)) fmt.Println(bytes.Equal(a, b)) fmt.Println(bytes.EqualFold(s, t)) }
该例测试结果为:
1 false true
1_1_3.字节切片前后缀检查函数
HasPrefix()函数和HasSuffix()函数可以检查字节切片的前后缀,并返回一个部卫星的检查结果。
(1)HasPrefix()函数。HasPrefix()函数的功能是检查字节切片s的前缀是否为prefix。如果是,则返回true,如果不是返回false。该函数的原型定义如下:
func HasPrefix(s, prefix []byte) bool
在函数HashPrefix中,参数s是需要检查的字节切片;参数prefix是前缀切片。
(2)HashSuffix()函数。功能是检查字节切片s的后缀是否为suffix,如果是返回true。函数原型定义如下:
func HasSuffix(s, suffix []byte) bool
在函数HasSuffix中,参数s是需要检查的字节切片;参数suffix是后缀切片。
例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("recover") prefix := []byte("re") suffix := []byte("ed") fmt.Println(bytes.HasPrefix(s, prefix)) fmt.Println(bytes.HasSuffix(s, suffix)) }
结果:
true false
1_1_4.字节切片位置索引函数
字节切片位置索引函数共有8个:Index()、IndexAny()、IndexByte()、IndexFunc()、IndexRune()、LastIndex()、LastIndexAny()和LastIndexFunc().函数原型如下:
func Index(s, sep []byte) int func IndexAny(s []byte, chars string) int func IndexByte(s []byte, c byte) int func IndexFunc(s []byte, f func(r rune) bool) int func IndexRune(s []byte, r rune) int func LastIndex(s, sep []byte) int func LastIndexAny(s []byte, chars string) int func LastIndexFunc(s []byte, f func(r rune) bool) int
(1)Index()函数功能是返回sep在s中第一次出现的位置索引(从0开始),如果sep中不在s中返回-1.
(2)IndexAny()函数的功能是把s结实为UTF-8编码的字节序列,返回chars中任何一个字符在s中第一次出现的位置索引;如果s中不包含chars中任何一个字符返回-1
(3)IndexByte()函数的功能是检查字节c在s中第一次出现的位置索引;如果s中不包含c则返回-1
(4)IndexFunc()函数的功能是把s解释成UTF-8字节序列,并返回第一个满足f(c)=true的字符c的位置索引。如果没有满足的则返回-1
(5)IndexRune()函数的功能是把s解释成UTF-8字节序列,并返回rune类型的字符r在s中的位置索引;如果s中不包含r则返回-1
(6)LastIIndex()函数的功能是返回sep在s中最后一次出现的位置索引,如果s中不包含sep则返回-1
(7)LastIndexAny()函数的功能是把s解释成UTF-8字节序列,返回chars中任一字符在s中最后出现的位置索引。如果chars为空或者s中不包含chars中的任意字符,则返回-1.
(8)LastIndexFunc()函数的功能是把s解释成UTF-8字节序列,返回满足f(s)=true的字符c在s中最后一次出现位置的索引。如果没找到 返回-1
示例如下:
package main import ( "bytes" "fmt" ) func main() { s := []byte("Google") sep := []byte("o") chars := "gle" var c byte = 'g' var r rune = 'l' fmt.Printf("切片%q在%q中的位置索引是: %d ", sep, s, bytes.Index(s, sep)) fmt.Printf("切片%q的任一字符在%q中的位置索引是: %d ", chars, s, bytes.IndexAny(s, chars)) fmt.Printf("byte型字符%q在%q中的位置索引是: %d ", c, s, bytes.IndexByte(s, c)) fmt.Printf("切片%q中第一个符合f()字符索引是: %d ", s, bytes.IndexFunc(s, f)) fmt.Printf("rune型字符%q在%q中的位置索引是: %d ", r, s, bytes.IndexRune(s, r)) fmt.Printf("切片%q在%q中最后的位置索引是: %d ", sep, s, bytes.LastIndex(s, sep)) fmt.Printf("切片%q的任一字符在%q中最后的位置索引是:%d ", chars, s, bytes.LastIndexAny(s, chars)) fmt.Printf("切片%q中最后一个符合f()字符索引是: %d ", s, bytes.LastIndexFunc(s, f)) } func f(a rune) bool { if a > 'k' { return true } else { return false } }
该例的测试结果为:
切片"o"在"Google"中的位置索引是: 1 切片"gle"的任一字符在"Google"中的位置索引是: 3 byte型字符'g'在"Google"中的位置索引是: 3 切片"Google"中第一个符合f()字符索引是: 1 rune型字符'l'在"Google"中的位置索引是: 4 切片"o"在"Google"中最后的位置索引是: 2 切片"gle"的任一字符在"Google"中最后的位置索引是:5 切片"Google"中最后一个符合f()字符索引是: 4
1_1_5.字节切片分割函数
字节切片分割函数共有6个:Fields()、FieldsFunnc()、Split()、SplitN()、SplitAfter()和SplitAfterN().函数原型如下:
func Fields(s []byte) [][]byte wq func FieldsFunc(s []byte, f func(rune) bool) [][]byte func Split(s, sep []byte) [][]byte func SplitAfter(s, sep []byte) [][]byte func SplitAfterN(s, sep []byte, n int) [][]byte func SplitN(s, sep []byte, n int) [][]byte
Fields()函数的功能是把字节切片s按照一个或者连续多个空白字符分割成多个字节切片,如果s只包含空白字符则返回空字节切片。其中参数s准备分割的字节切片。示例如下:
package main import ( "bytes" "fmt" ) func main() { s := []byte("I'm a student.") for _, f := range bytes.Fields(s) { fmt.Printf("%q", f) } }
测试结果为:
"I'm""a""student."
FieldsFunc()函数功能是把s解释为UTF-8编码的字符序列,对于每个Unicode字符c,如果f(c)返回true就把c作为分割字符对s进行拆分。如果所有字符都满足f(c)为true,则返回空的切片。示例:
package main import ( "bytes" "fmt" ) func main() { s := []byte("小明和爸爸和妈妈") for _, f := range bytes.FieldsFunc(s, f) { fmt.Printf("%q", f) } } func f(a rune)bool{ if a=='和'{ return true }else{ return false } }
测试结果为:
"小明""爸爸""妈妈"
Split()函数的功能是把s用sep分割成多个字节切片并返回。如果sep为空,Split则把s切分成每个字节切片对应一个UTF-8字符。Split()等效于参数为n的SplitN()函数。示例:
package main import ( "bytes" "fmt" ) func main() { s := []byte("Hello,world") sep := []byte(",") for _, f := range bytes.Split(s, sep) { fmt.Printf("%q", f) } }
测试结果为:
"Hello""world"
SplitAfter()函数的功能是把s用sep分割成多个字节切片并返回。如果sep为空,Split则把s切分成每个字节切片对应一个UTF-8字符。参数n决定返回长度,n>0,最多返回n个子切片;n==0返回s n< 0返回所有子切片。示例:
package main import ( "bytes" "fmt" ) func main() { s := []byte("南瓜,黄瓜,西红柿,茄子") sep := []byte(",") n := 2 for _, f := range bytes.SplitN(s, sep, n) { fmt.Printf("%q ", f) } for _, f := range bytes.SplitN(s, sep, 0) { fmt.Printf("%q ", f) } for _, f := range bytes.SplitN(s, sep, -1) { fmt.Printf("%q", f) } }
测试结果为:
"南瓜" "黄瓜,西红柿,茄子" "南瓜""黄瓜""西红柿""茄子"
SplitAfter()函数功能使用sep作为后缀把s切分成多个字节切片并返回。如果sep为空,则把s切分成每个字节切片对应一个UTF-8字符。示例:
package main import ( "bytes" "fmt" ) func main() { s := []byte("managerteacherworkerfarmerstudent") sep := []byte("er") for _, f := range bytes.SplitAfter(s, sep) { fmt.Printf("%q", f) } }
测试结果为:
"manager""teacher""worker""farmer""student"
SplitN()函数功能是用sep作为后缀把s切分成多个字节切片并返回。如果sep为空,则把s切分成每个字节切片对应一个UTF-8字符。参数n决定返回切片的长度:如果n>0,最多返回n个子字节切片,子切片可能包含未切分的字节序列;如果n=0,返回空切片如果n< 0返回所有子切片。示例:
package main import ( "bytes" "fmt" ) func main() { s := []byte("managerteacherworkerfarmerstudent") sep := []byte("er") n := 3 for _, f := range bytes.SplitAfterN(s, sep, n) { fmt.Printf("%q", f) } fmt.Println() for _, f := range bytes.SplitAfterN(s, sep, 0) { fmt.Printf("%q", f) } fmt.Println() for _, f := range bytes.SplitAfterN(s, sep, -1) { fmt.Printf("%q", f) } }
测试结果为:
"manager""teacher""workerfarmerstudent" "manager""teacher""worker""farmer""student"
1_1_6.字节切片大小写处理函数
字节切片大小写处理函数共有7个:Title()、ToTitle()、ToTitleSpecial()、ToLower()、ToLowerSpecial()、ToUpper()和ToUpperSpecial().以下为函数原型:
func Title(s []byte) []byte func ToTitle(s []byte) []byte func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte func ToLower(s []byte) []byte func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte func ToUpper(s []byte) []byte func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte
(1)Title()函数的功能是返回s的一个副本,把s中的每个单词的首字母改为Unicode字符的大写。
(2)ToTitle()函数的功能是返回s的一个副本,并把其中的所有的Unicode字符转为大写。
(3)ToTitleSpecial()函数功能是返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转换成大写。
package main import ( "bytes" "fmt" "unicode" ) func main() { s := []byte("hello,world!") fmt.Println(string(bytes.Title(s))) fmt.Println(string(bytes.ToTitle(s))) fmt.Println(string(bytes.ToTitleSpecial(unicode.AzeriCase, s))) }
该例测试结果为:
Hello,World! HELLO,WORLD! HELLO,WORLD!
(4)ToLower()函数的功能是返回s的一个副本,并把其中的所有的Unicode字符转为小写.
(5)ToLowerSpecial()函数功能是返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转换成小写.
package main import ( "bytes" "fmt" "unicode" ) func main() { s := []byte("Hello,World!") fmt.Println(string(bytes.ToLower(s))) fmt.Println(string(bytes.ToLowerSpecial(unicode.AzeriCase, s))) }
该例测试结果为:
hello,world!
hello,world!
(6)ToUpper()函数的功能是返回s的一个副本,并把其中的所有的Unicode字符转为大写。
(7)ToUpperSpecial()函数功能是返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转换成大写。
package main import ( "bytes" "fmt" "unicode" ) func main() { s := []byte("hello,world!") fmt.Println(string(bytes.ToUpper(s))) fmt.Println(string(bytes.ToUpperSpecial(unicode.AzeriCase, s))) }
该例测试结果为:
HELLO,WORLD!
HELLO,WORLD!
1_1_7.子字节切片处理函数
子字节切片处理函数共有9个:Trim()、TrimFunc()、TrimLeft()、TrimLeftFunc()、TrimRight()、TrimRightFunc()、TrimSpace()、TrimPrefix()和TrimSuffix()
func Trim(s []byte, cutset string) []byte func TrimFunc(s []byte, f func(r rune) bool) []byte func TrimLeft(s []byte, cutset string) []byte func TrimLeftFunc(s []byte, f func(r rune) bool) []byte func TrimRight(s []byte, cutset string) []byte func TrimRightFunc(s []byte, f func(r rune) bool) []byte func TrimSpace(s []byte) []byte func TrimPrefix(s, prefix []byte) []byte func TrimSuffix(s, suffix []byte) []byte
(1)Trim()函数的功能是返回s的子字节切片,cutset中任意出现在s的首部和尾部的连续字符将被删除。例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("hello,world!") cutset := "hold!" fmt.Println(string(bytes.Trim(s, cutset))) }
测试结果为:
ello,wor
(2)TrimFunc()函数功能是返回s的子字节切片,不包含s首部和尾部连接的满足f(c)=true的字符c。例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("hello,world!") fmt.Println(string(bytes.TrimFunc(s, f))) } func f(a rune) bool { if a == 'h' || a == '!' { return true } else { return false } }
测试结果为:
ello,world
(3)TrimLeft()函数的功能是返回s的子字节切片,cutset中任意出现在s首部的连续字符被删除。例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("hello,world!") cutset := "hold" fmt.Println(string(bytes.TrimLeft(s, cutset))) }
测试结果为:
ello,world!
(4)TrimLeftFunc()函数功能是返回s的一个子字节切片、不包含s首部连续满足f(c)=true的字符c。例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("hello,world!") fmt.Println(string(bytes.TrimLeftFunc(s, f))) } func f(a rune) bool { if a == 'h' || a == '!' { return true } else { return false } }
测试结果为:
ello,world!
(5)TrimRight()
package main import ( "bytes" "fmt" ) func main() { s := []byte("hello,world!") cutset := "hold!" fmt.Println(string(bytes.TrimRight(s, cutset))) }
测试结果为:
hello,wor
(6)TrimRightFunc()函数功能是返回s的一个子字节切片、不包含s尾部连续满足f(c)=true的字符c。例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte("hello,world!") fmt.Println(string(bytes.TrimRightFunc(s, f))) } func f(a rune) bool { if a == 'h' || a == '!' { return true } else { return false } }
测试结果为:
hello,world
(7)TrimSpace()函数功能是返回s的一个子字节切片,并删除s中开始和结尾处的连续的Unicode空白字符。例如:
package main import ( "bytes" "fmt" ) func main() { s := []byte(" hello,world! ") fmt.Println(string(bytes.TrimSpace(s))) }
测试结果为:
hello,world!
(8)TrimPrefix()函数功能是返回s的一个子字节切片,并删除前缀为prefix的部分
(9)TrimSuffix()函数功能是返回s的一个子字节切片,并删除后缀为suffix的部分
1_2.Buffer
在bytes包中,缓冲区(Buffer)是最常用的对字节切片进行I/O操作的对象。Buffer对象的定义如下:
type Buffer struct { // contains filtered or unexported fields }
默认情况下Buffer对象没有定义初始值,Buffer使用结构体自带的一个[64]byte数组作为存储空间。当超出限制时,另创建一个两倍的存储空间,并复制未读取的数据。当Buffer里的数据被完全读取后,会将写入位置重置到底层数据的开始处。因此只要读写操作平衡,就无须担心内存会持续增长。
1_2_1.Buffer对象创建函数
可以使用NewBuffer(buf []byte)和NewBufferString()函数创建Buffer对象,他们分别使用字节切片和字符串对Buffer进行初始化。
(1)NewBuffer()函数。功能是创建一个Buffer,并用字节切片buf对它进行初始化。buf可以直接用来作为准备要读的数据;也可以用来指定写缓冲区的大小,这时要提前为buf分配内存空间,但是len(buf)为0.该函数的原型定义如下:
func NewBuffer(buf []byte) *Buffer
(2)NewBufferString()函数。功能是创建一个Buffer,并用字符串s对它进行初始化。它通常用于读取已经存在的数据。该函数的原型定义如下:
func NewBufferString(s string) *Buffer
1_2_2.Buffer写操作方法
对Buffer对象的写操作方法共有5个函数:Write(),WriteByte(),WriteRune(),WriteString()和WriteTo()方法。原型定义如下:
func (b *Buffer) Write(p []byte) (n int, err error) func (b *Buffer) WriteByte(c byte) error func (b *Buffer) WriteRune(r rune) (n int, err error) func (b *Buffer) WriteString(s string) (n int, err error) func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)
(1)Write()方法.功能是把字节切片p写入Buffer中,该方法执行结束返回成功写入的字节数n和错误类型err。如果返回的n满足n==len(p),则err总是为nil,如果数据太大则Write会panic并产生ErrTooLarge异常。示例如下(参数p是要写入的切片):
package main import ( "bytes" "fmt" ) func main() { p := []byte("Hello,world!") b := bytes.NewBuffer(nil) n, err := b.Write(p) fmt.Println(string(b.Bytes()), n, err) }
测试结果为:
Hello,world! 12 <nil>
(2)WriteByte()方法。功能是写入一个字节,总是返回nil。这个返回值只是为了匹配bufio.Writer的Write函数。如果内部数据太大,WriteByte会panic并产生ErrTooLarge异常。示例如下(c是要写入的自己额数据,比如ASCII字符):
package main import ( "bytes" "fmt" ) func main() { var c1, c2 byte = 'G', 'o' b := bytes.NewBuffer(nil) err := b.WriteByte(c1) b.WriteByte(c2) fmt.Println(string(b.Bytes()), err) }
测试结果为:
Go <nil>
(3)WriteRune()方法。功能是把一个Unicode字符的UTF-8编码写入Buffer,并返回写入字节数n。err总是nil,这个返回类型是为了和bufio.Writer的WriteRune函数匹配。如果Buffer的缓冲区太大,则WriteRune会panic并产生ErrTooLarge异常。示例如下(参数r是要写入的rune类型的字符):
package main import ( "bytes" "fmt" ) func main() { var r1, r2 rune = '中', '国' b := bytes.NewBuffer(nil) b.WriteRune(r1) b.WriteRune(r2) fmt.Println(string(b.Bytes())) }
测试结果为:
中国
(4)WriteString()方法.功能是把s写入Buffer,返回值n为len(s),err总是为nil。如果内部缓冲区太大,WriteString会panic并产生ErrTooLarge异常。示例如下(参数s是要写入的字符串):
package main import ( "bytes" "fmt" ) func main() { s := "你好,世界!" b := bytes.NewBuffer(nil) n, err := b.WriteString(s) fmt.Println(string(b.Bytes()), n, err) }
测试结果为:
你好,世界! 18 <nil>
(5)WriteTo()方法。功能是把Buffer中的数据写入到I/O对象w中,直到数据为空或者遇到错误,返回值n总是足够用int表示,使用int64类型是为了和io.WriteTo接口匹配。任何写入时遇到的错误都会被返回。示例如下(参数w是要写入的I/O对象):
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Golang") b := bytes.NewBuffer(buf) w := bytes.NewBuffer(nil) n, err := b.WriteTo(w) fmt.Println(string(w.Bytes()), n, err) }
测试结果为:
Golang 6 <nil>
1_2_3.Buffer读操作方法
对Buffer的读操作方法共有6个:Read()、ReadByte()、ReadBytes()、ReadFrom()、ReadRune()和ReadString()方法,原型定义如下:
func (b *Buffer) Read(p []byte) (n int, err error) func (b *Buffer) ReadByte() (c byte, err error) func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) func (b *Buffer) ReadRune() (r rune, size int, err error) func (b *Buffer) ReadString(delim byte) (line string, err error)
(1)Read()方法.功能是从Buffer中读取len(p)个字节,并复制到p中;如果Buffer中未读数据不足len(p),则把所有的数据都复制到p中。该方法执行完,返回实际读取的字节数n和错误类型err。如果Buffer中没有数据,则err为io.EOF(除非len(p)为0);否则err为nil。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Hello,world!") b := bytes.NewBuffer(buf) var p [8]byte n, err := b.Read(p[:]) fmt.Println(string(p[:n]), n, err) }
测试结果为:
Hello,wo 8 <nil>
(2)ReadByte()方法.功能是从Buffer中读取一个字节并返回,如果没有数据可读则err为io.EOF。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Golang") b := bytes.NewBuffer(buf) c, err := b.ReadByte() fmt.Println(string(c), err) }
测试结果为:
G <nil>
(3)ReadBytes()方法.功能是从Buffer中读取数,直到第一次遇到分隔符"delim",把已读取的数据包括"delim"作为字节切片返回。如果在读取到"delim"前出现错误,则返回已经读取的数据和那个错误(通常是io.EOF).只有返回的数据不可以"delim"结尾时,ReadBytes才返回err非空。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Hello,world!") b := bytes.NewBuffer(buf) var delim byte = ',' line, err := b.ReadBytes(delim) fmt.Println(string(line), err) }
测试结果为:
Hello, <nil>
(4)ReadFrom()方法.功能是从I/O接口对象r中读取数据,并写入到Buffer中,直到r.Read返回io.EOF,除了io.EOF之外的错误会被ReadFrom返回。返回值n为以读取的字节数,err为r.Read返回的错误。如果读取的数据太大,ReadFrom会panic并产生ErrToolarge异常。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("中华人民共和国") r := bytes.NewBuffer(buf) b := bytes.NewBuffer(nil) n, err := b.ReadFrom(r) fmt.Println(string(b.Bytes()), n, err) }
测试结果为:
中华人民共和国 21 <nil>
(5)ReadRune()方法.功能是从Buffer中读取一个unicode字符,同时返回它的UTF-8编码,如果没有数据可读则返回io.EOF。如果读取的不是UTF-8编码字节序列,则读取一个字节并返回U+FFFD.示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("中华人民共和国") b := bytes.NewBuffer(buf) r, size, err := b.ReadRune() fmt.Println(string(r), size, err) }
测试结果为:
中 3 <nil>
(6)ReadString()方法.功能是读取数据指导遇到分隔符"delim",并把已读取的数据包含"delim"作为string返回。如果在遇到"delim"前出错,则把已读数据作为string和遇到的错误(通常是io.EOF)返回。当返回的string不以"delim"结尾时,才会返回非空err。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Golang is a beautiful language,I like it!") b := bytes.NewBuffer(buf) var delim byte = ',' line, err := b.ReadString(delim) fmt.Println(line, err) }
测试结果为:
Golang is a beautiful language, <nil>
1_2_4.Buffer其他操作方法
对Buffer对象的其他操作方法共有8个:Byte()、Len()、Next()、Reset()、String()、Truncate()、UnreadByte()和UnreadRune(),函数原型:
func (b *Buffer) Bytes() []byte func (b *Buffer) Len() int func (b *Buffer) Next(n int) []byte func (b *Buffer) Reset() func (b *Buffer) String() string func (b *Buffer) Truncate(n int) func (b *Buffer) UnreadByte() error func (b *Buffer) UnreadRune() error
(1)Bytes()方法。功能是返回Buffer中未读取的字节数。它满足条件len(b.Bytes())=b.Len()。
(2)Len()方法。功能是返回buffer中未读取数据的字节数。它满足条件b.Len()=len(b.Bytes()).示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Golang is a beautiful language,I like it!") b := bytes.NewBuffer(buf) var delim byte = ',' fmt.Println("未执行读取操作前Buffer中数据和字节数") fmt.Println(string(b.Bytes()), b.Len()) b.ReadString(delim) fmt.Println("执行读操作后Buffer中数据和字节数") fmt.Println(string(b.Bytes()), b.Len()) }
测试结果为:
未执行读取操作前Buffer中数据和字节数 Golang is a beautiful language,I like it! 41 执行读操作后Buffer中数据和字节数 I like it! 10
(3)Next()方法。功能是返回Buffer中下n个未读取的字节没,本次读取会修改Buffer中的读取位置。如果Buffer中未读数据不足n字节,则返回全部未读数据。返回的字节切片在下次读或写前有效。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Golang") b := bytes.NewBuffer(buf) fmt.Println(string(b.Next(4))) fmt.Println(string(b.Next(4))) }
测试结果为:
Gola
ng
(4)Reset()方法。功能是把Buffer中的数据清空,等同于b.Truncate(0).
(5)String()方法。功能是把Buffer中的未读取数据作为string返回。如果Buffer是个nil指针,则返回"<nil>"
(6)Truncate()方法。功能是只保留前n个字节的数据并清除其余数据。当n<或者n>b.Len()时,则Truncate导致panic,当n=0时,等同于b.Reset()。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Hello,world!") b := bytes.NewBuffer(buf) fmt.Println("未执行Reset前Buffer中的内容:", string(b.Bytes())) b.Truncate(5) fmt.Println("执行Truncate后Buffer中内容:", string(b.Bytes())) b.Reset() fmt.Println("执行Reset后Buffer中内容:", string(b.Bytes())) }
测试结果为:
未执行Reset前Buffer中的内容: Hello,world!
执行Truncate后Buffer中内容: Hello
执行Reset后Buffer中内容:
(7)UnreadByte()方法。功能是取消上次读取的最后一个字节,如果上次读取之后有过写操作,则返回错误。示例如下:
package main import ( "bytes" "fmt" ) func main() { buf := []byte("Golang") b := bytes.NewBuffer(buf) fmt.Println(string(b.Next(3))) b.UnreadByte() fmt.Println(string(b.Bytes())) }
测试结果为:
Gol
lang
(8)UnreadRune()方法。功能是取消上次ReadRune()读取的Unicode字符。如果最近一次写操作不是ReadRune,则返回一个错误。示例如下
package main import ( "bytes" "fmt" ) func main() { buf := []byte("中华人民共和国") b := bytes.NewBuffer(buf) b.ReadRune() b.ReadRune() b.ReadRune() b.UnreadRune() fmt.Println(string(b.Bytes())) }
测试结果为:
人民共和国
1_3.Reader
Reader是另一个可以对字节切片进行操作的对象,与Buffer对象不同的是,Reader对象只是从字节切片中读取数据,不能写入数据,但是,Reader对象支持对字节切片进行定位操作。Reader对象定义如下:
type Reader struct { // contains filtered or unexported fields }
1_3_1.Reader对象创建函数
Reader对象的创建函数式NewReader(),它的作用是创建一个Reader,数据为字节切片b,该函数原型定义如下:func NewReader(b []byte) *Reader
1_3_2.Reader对象操作方法
Reader对象的操作方法共有8个:Len()、Read()、ReadAt()、ReadByte()、ReadRune()、Seek()、UnreadByte()和UnreadRune()。方法原型为:
func (r *Reader) Len() int func (r *Reader) Read(b []byte) (n int, err error) func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) func (r *Reader) ReadByte() (b byte, err error) func (r *Reader) ReadRune() (ch rune, size int, err error) func (r *Reader) Seek(offset int64, whence int) (int64, error) func (r *Reader) UnreadByte() error func (r *Reader) UnreadRune() error func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
(1)Len()方法。功能是返回Reader中读取的字节数。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("Golang") r := bytes.NewReader(b) fmt.Println(r.Len()) }
测试结果为:
6
(2)Read()方法。功能是从Reader中读取Len(b)个字节,返回已读取的字节数。如果遇到错误则返回错误(通常是io.EOF)。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("Golang") var buf [3]byte r := bytes.NewReader(b) n, err := r.Read(buf[:]) fmt.Println(string(buf[:n]), n, err) n, err = r.Read(buf[:]) fmt.Println(string(buf[:n]), n, err) n, err = r.Read(buf[:]) fmt.Println(string(buf[:n]), n, err) }
测试结果为:
Gol 3 <nil>
ang 3 <nil>
0 EOF
(3)ReadAt()方法。功能是从Reader中偏移为off字节的为孩子读取len(b)个字节,并返回已读取得字节数;如果遇到错误则返回错误(通常是io.EOF)。ReadAt读取的数据不会从Reader中清除。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("Golang") var buf [3]byte r := bytes.NewReader(b) n, err := r.ReadAt(buf[:], 2) fmt.Println(string(buf[:n]), n, err) n, err = r.ReadAt(buf[:], 3) fmt.Println(string(buf[:n]), n, err) n, err = r.ReadAt(buf[:], 4) fmt.Println(string(buf[:n]), n, err) }
测试结果为:
lan 3 <nil> ang 3 <nil> ng 2 EOF
(4)ReadByte()方法。功能是从Reader中读取一个字节并返回,如果遇到错误返回错误(通常是io.EOF)。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("Golang") r := bytes.NewReader(b) c, err := r.ReadByte() fmt.Println(string(c), err) }
测试结果为:
G <nil>
(5)ReadRune()方法。功能是从Reader中按照UTF-8编码读取一个Unicode字符,返回此字符,其字符的UTF-8编码占用的字节数,如果遇到错误(通常是io.EOF)。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("中华人民共和国") r := bytes.NewReader(b) ch, size, err := r.ReadRune() fmt.Println(string(ch), size, err) }
测试结果为:
中 3 <nil>
(6)Seek()方法。功能是实现了io.Seeker节后方法,用于设置下次读或写操作的位置,返回新的偏移位置字节数和错误(如果有).当whence=0,从起始位置计算offset,当whence=1,从当前位置计算offset,当whence=2从尾部位置计算offset。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("中华人民共和国") r := bytes.NewReader(b) r.Seek(3, 0) //从起始位置偏移3,应该是'华'字 ch, size, err := r.ReadRune() fmt.Println(string(ch), size, err) r.Seek(3, 1) //从当前位置偏移3,应该是'民'字 ch, size, err = r.ReadRune() fmt.Println(string(ch), size, err) r.Seek(-6, 2) //从尾部位置偏移3,应该是'和'字 ch, size, err = r.ReadRune() fmt.Println(string(ch), size, err) }
测试结果为:
华 3 <nil> 民 3 <nil> 和 3 <nil>
(7)UnreadByte()方法。功能是取消上次读取的最后一个字节,如果Buffer没有被读取过则UnreadByte也返回一个错误。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("Golang") var buf [6]byte r := bytes.NewReader(b) //Buffer还没被读取过,返回一个错误 err := r.UnreadByte() fmt.Println(err) n, _ := r.Read(buf[:]) //第一次读取 fmt.Println(string(buf[:n]), n) err = r.UnreadByte() //取消第一次读取的最后一个字节'g' fmt.Println(err) n, _ = r.Read(buf[:]) //第二次读取,Buffer中只剩'g'了 fmt.Println(string(buf[:n]), n) }
测试结果为:
bytes.Reader: at beginning of slice Golang 6 <nil> g 1
(8)UnreadRune()方法。功能是取消上次ReadRune读取的Unicode字符。如果上次读取操作不是ReadRune,则返回错误。示例如下:
package main import ( "bytes" "fmt" ) func main() { b := []byte("中华人民共和国") var buf [3]byte r := bytes.NewReader(b) r.Read(buf[:]) //用Read读取第一个Unicode字符'中' err := r.UnreadRune() fmt.Println(err) ch, _, _ := r.ReadRune() //用ReadRune读取第二个Unicode字符'华' fmt.Println(string(ch)) err = r.UnreadRune() //取消上次读取的Unicode字符 fmt.Println(err) ch, _, _ = r.ReadRune() //用ReadRune重新读取第二个Unicode字符'华' fmt.Println(string(ch)) }
测试结果为:
bytes.Reader: previous operation was not ReadRune 华 <nil> 华
2.io包
在Java中按照对io流处理的基本单位可以分为这样几个模块(实际上JavaAPI的package组织形式也是按照这种分类方法)
字节流(数据流中的最小单元为一个字节):InputStream和OutputStream是所有字节输入流、输出流的父类,二者都直接继承自java.lang.Object
字符流(多用于读写文本文件。文本文件存放了用特定字符编码的字符):Reader和Writer是所有字符输入流、输出流的父类,二者都直接继承自java.lang.Object
在Go语言中字节流和字符流处理的类型并没有被分隔,在bytes包中的三大部分:[]byte处理函数、Buffer和Reader都是对最基本的数据单位字节byte的处理,而这三部分不仅有字节处理函数还有字符处理函数,因为无论是字节流还是字符流最根本上还是对字节的操作。但是这三部分并没有明显的流的概念,只是简单地停留在字节数据操作的级别。
Go语言真正定义流的概念是在io包中io包中包含了各种流类型的定义以及关闭和复制流等基本操作(不过非常有限),官方给出这样的说明Package io provides basic interfaces to I/O primitives意思是:io包提供了关于I/O基元的基本接口,可以理解为它主要是定义了I/O的容器(或者说是通道)
而bufio包中详细定义了对流读写细节操作的方法,对I/O流的操作的各种方法基本上都在这里。其操作的对象也就是io包中定义的类型。
3.bufio包
Go语言标准库bufio包,实现了对数据I/O接口的缓冲功能。它封装与接口io.ReadWriter,io.Reader和io.Writer中,并对应创建对象ReadWriter、Reader或Writer,在提供缓冲的同时实现了一些文本基本I/O操作功能。
3_1.ReadWriter对象
ReadWriter对象可以对数据I/O接口io.ReadWriter进行输入输出缓冲操作,ReadWriter结构定义如下:type ReadWriter struct { *Reader *Writer }
默认情况下,ReadWriter对象中存放了一对Reader和Writer指针,它同时提供了对数据I/O对象的读写缓冲功能。
可以使用NewReadWriter()函数创建ReadWriter对象,该函数的功能是根据指定的Reader和Writer创建一个ReadWriter对象,ReadWriter对象将会向底层io.ReadWriter接口写入数据,或者从io.ReadWriter接口读取数据。该函数原型声明如下:
func NewReadWriter(r *Reader, w *Writer) *ReadWriter
在函数NewReadWriter()中,参数r是要读取的来源Reader对象;参数w是要写入的目的Writer对象。
3_2.Reader对象
Reader对象可以对数据I/O接口io.Reader进行输入缓冲操作,Reader结构定义如下:
type Reader struct { // contains filtered or unexported fields }
默认情况下Reader对象没有定义初始值,输入缓冲区最小值为16.当超过限制时,另创建一个2倍的存储空间。
3_2_1.Reader对象创建函数
Reader对象的创建函数共有2个:NewReader()和NewReaderSize(),下面分别介绍:
(1)NewReader()函数。功能是按照缓冲区默认长度创建Reader对象,Reader对象会从底层io.Reader接口读取尽量多的数据进行缓冲。该函数原型声明如下:
func NewReader(rd io.Reader) *Reader
在函数NewReader()中,参数rd是io.Reader接口,Reader对象将从该接口读取数据.
(2)和NewReaderSize()函数。功能是按照指定的缓冲区长度创建Reader对象,Reader对象会从底层io.Reader接口读取尽量多的数据进行缓存。该函数的原型声明如下:
func NewReaderSize(rd io.Reader, size int) *Reader
在函数NewReaderSize()中,参数rd是io.Reader接口,参数size是指定的缓冲区字节长度。
3_2_2.Reader对象操作方法
Reader对象的操作方法共有12个:Read()、ReadByte()、ReadBytes()、ReadLine()、ReadRune()、ReadSlice()、ReadString()、UnreadByte()、UnreadRune()、Buffered()、Peek()、WriteTo()它们的原型声明如下:
func (b *Reader) Read(p []byte) (n int, err error) func (b *Reader) ReadByte() (c byte, err error) func (b *Reader) ReadBytes(delim byte) (line []byte, err error) func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) func (b *Reader) ReadRune() (r rune, size int, err error) func (b *Reader) ReadSlice(delim byte) (line []byte, err error) func (b *Reader) ReadString(delim byte) (line string, err error) func (b *Reader) UnreadByte() error func (b *Reader) UnreadRune() error func (b *Reader) Buffered() int func (b *Reader) Peek(n int) ([]byte, error) func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
(1)Read()方法。功能是读取数据,并存放到字节切片p中。Read()执行结束会返回已读取的字节数,因为最多只调用底层的io.Reader一次,所以返回的n可能小于len(p);当字节流结束时,n为0,err为io.EOF。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("中华人民共和国") rd := bytes.NewReader(data) r := bufio.NewReader(rd) var buf [128]byte n, err := r.Read(buf[:]) fmt.Println(string(buf[:n]), n, err) }
测试结果为:
中华人民共和国 21 <nil>
(2)ReadByte()方法。功能是读取并返回一个字节。如果没有字节可读。则返回错误信息。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("Golang") rd := bytes.NewReader(data) r := bufio.NewReader(rd) c, err := r.ReadByte() fmt.Println(string(c), err) }
测试结果为:
G <nil>
(3)ReadBytes()方法。功能是读取数据直到遇到第一个分隔符"delim",并返回读取的字节序列(包括"delim").如果在读到第一个"dleim"之前出错,它返回已读的数据和那个错误(通常是io.EOF)。只有当返回的数据不以"delim"结尾时,返回的err才不为空值。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("Hello,world!") rd := bytes.NewReader(data) r := bufio.NewReader(rd) var delim byte = ',' line, err := r.ReadBytes(delim) fmt.Println(string(line), err) }
测试结果为:
Hello, <nil>
(4)ReadLine()方法。功能是一个低级的用于读取一行数据的原语,大多数调用者应该使用ReadBytes(' ')或者ReadString(' ').ReadLine试图返回一行,不包括结尾的回车字符。如果一行太长了(超过缓冲区长度),canshu isPrefix会 设置为true并且只返回前面的数据,剩余的数据会在以后的调用中返回。当返回最后一行数据时,参数isPrefix会设置为false。返回的字节切片只在下一次调用ReadLine前有效。ReadLine或者返回一个非空的字节切片或者返回一个错误。但他们不会同时返回。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("Golang is a beautiful language. I like it!") rd := bytes.NewReader(data) r := bufio.NewReader(rd) line, prefix, err := r.ReadLine() fmt.Println(string(line), prefix, err) }
测试结果为:
Golang is a beautiful language. false <nil>
(5)ReadRune()方法。功能是读取下一个UTF-8编码的字符,并返回Unicode编码和字节数。如果编码错误,ReadRune只读取一个字节并返回unicode.ReplacementChar(U+FFFD)和长度1.示例如下
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("中华人民共和国") rd := bytes.NewReader(data) r := bufio.NewReader(rd) ch, size, err := r.ReadRune() fmt.Println(string(ch), size, err) }
测试结果为:
中 3 <nil>
(6)ReadSlice()方法。功能是读取数据直到分隔符"delim"处,并返回读取数据的字节切片,下次读取数据时返回的切片会失效。如果ReadSlice在查找到"delim"之前遇到错误,它返回读取的所有数据和那个错误(通常是io.EOF)。如果缓冲区满时也没有查找到delim,则返回ErrBufferFull错误。因为ReadSlice返回的数据会再下次I/O操作是被覆盖,大多调用者应该使用ReadBytes或者ReadString。只有当line不以"delim"结尾时,ReadSlice才会返回非空err。示例如下;
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("apple,banana,pear") rd := bytes.NewReader(data) r := bufio.NewReader(rd) var delim byte = ',' line, err := r.ReadSlice(delim) fmt.Println(string(line), err) line, err = r.ReadSlice(delim) fmt.Println(string(line), err) line, err = r.ReadSlice(delim) fmt.Println(string(line), err) }
测试结果为:
apple, <nil> banana, <nil> pear EOF
(7)ReadString()方法。功能是读取数据直到分隔符delim第一次出现,并返回一个包含delim的字符串。如果ReadString在读取到delim前遇到错误,它返回已读字符串和那个错误(通常是io.EOF)。只有当返回的字符串不以delim结尾时,ReadString才返回非空err。示例如下:
<div class="cnblogs_code" style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding: 5px;"><pre>apple, <nil><span style="color: #000000;"> banana, </span><nil><span style="color: #000000;"> pear EOF</span></pre></div>
测试结果为:
apple, <nil>
(8)UnreadByte()方法。 功能是取消已读的最后一个字节(即把字节重新放回读取缓冲区的前部)。只有最近一次读取的单个字节才能取消读取
(9)UnreadRune()方法。 功能是取消读取最后一次读取的unicode字符。如果最后一次读取操作不是ReadRune,会返回一个错误(在这方面它比UnreadByte更严格,因为UnreadByte会取消上次任意读操作的最后一个字节)。
(10)Buffered()方法。功能是返回可从缓冲区读出数据的字节数。示例如下;
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("中华人民共和国") rd := bytes.NewReader(data) r := bufio.NewReader(rd) var buf [12]byte n, err := r.Read(buf[:]) //第一次执行Read读取4个unicode字符 fmt.Println(string(buf[:n]), n, err) rn := r.Buffered() fmt.Printf("还可以从缓冲区中读取%d个字节 ", rn) n, err = r.Read(buf[:]) //第二次读取了剩余的3个unicode字符 fmt.Println(string(buf[:n]), n, err) rn = r.Buffered() fmt.Printf("还可以从缓冲区中读取%d个字节 ", rn) }
测试结果为:
中华人民 12 <nil> 还可以从缓冲区中读取9个字节 共和国 9 <nil> 还可以从缓冲区中读取0个字节
(11)Peek()方法。功能是读取指定字节数的数据,这些被读取的数据不会从缓冲区中清除。在下次读取之后,本次返回的字节切片会失效。如果Peek返回的字节数不足n字节,则会同时返回一个错误说明原因;如果n比缓冲区要大,则错误为ErrBufferFull。该方法示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { data := []byte("中华人民共和国") rd := bytes.NewReader(data) r := bufio.NewReader(rd) b1, err := r.Peek(9) fmt.Println(string(b1), err) b1, err = r.Peek(18) fmt.Println(string(b1), err) b1, err = r.Peek(27) fmt.Println(string(b1), err) }
测试结果为:
中华人 <nil> 中华人民共和 <nil> 中华人民共和国 EOF
(12)WriteTo()
3_3.Writer对象
Writer对象可以对数据I/O接口io.Writer进行输出缓冲操作,Writer结构定义如下:
type Writer struct { // contains filtered or unexported fields }
默认情况下Writer对象没有定义初始值,如果输出缓冲过程中发生错误,则数据写入操作立刻被终止,后续的写操作都会返回写入异常错误。
3_3_1.Writer对象创建函数
Writer对象创建函数共有两个:NewWriter()和NewWriterSize(),下面分别介绍:
(1)NewWriter()函数。功能是按照默认缓冲区创建Writer对象,Writer对象会将缓冲区的数据批量写入底层io.Writer接口。该函数的声明如下:
func NewWriter(wr io.Writer) *Writer
在函数中,参数wr是io.Writer接口,Writer对象会数据写入该接口。
(2)NewWriterSize()函数。功能是按照指定的缓冲区长度创建Writer对象,Writer对象会将缓存的数据批量写入底层io.Writer接口。该函数的原型声明如下:
func NewWriterSize(wr io.Writer, size int) *Writer
在函数主公,参数wr是io.Writer接口,参数size是指定的缓冲区字节长度.
3_3_2.Writer对象操作函数
Writer对象的操作方法共有8个:Available()、Buffered()、Flush()、Write()、WriteByte()、WriteRune()、WriteString()、和ReadFrom().它们的原型声明如下:
func (b *Writer) Available() int func (b *Writer) Buffered() int func (b *Writer) Flush() errorf func (b *Writer) Write(p []byte) (nn int, err error) func (b *Writer) WriteByte(c byte) error func (b *Writer) WriteRune(r rune) (size int, err error) func (b *Writer) WriteString(s string) (int, error) func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
(1)Available()方法。功能是返回缓冲区中未使用的字节数。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) p := []byte("Hello,world!") fmt.Println("写入前为使用的缓冲区为:", w.Available()) w.Write(p) fmt.Printf("写入%q后,未使用的缓冲区为:%d ", string(p), w.Available()) }
测试结果为:
写入前为使用的缓冲区为: 4096
写入"Hello,world!"后,未使用的缓冲区为:4084
(2)Buffered()方法。功能是返回已写入当前缓冲区中的字节数,示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) p := []byte("Hello,world!") fmt.Println("写入前写入字节数为:", w.Buffered()) w.Write(p) fmt.Printf("写入%q后,写入的字节数为:%d ", string(p), w.Buffered()) w.Flush() fmt.Println("执行Flush方法后,写入的字节数为:", w.Buffered()) }
测试结果为:
写入前写入字节数为: 0 写入"Hello,world!"后,写入的字节数为:12 执行Flush方法后,写入的字节数为: 0
(3)Flush()方法。功能是把缓冲区中的数据写入底层的io.Writer,并返回错误信息。如果成功写入,error返回nil,否则error返回错误原因。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) p := []byte("Hello,world!") w.Write(p) fmt.Printf("未执行Flush缓冲区输出%q. ", string(wr.Bytes())) w.Flush() fmt.Printf("执行Flush后,缓冲区输出%q.", string(wr.Bytes())) }
测试结果为:
未执行Flush缓冲区输出"".
执行Flush后,缓冲区输出"Hello,world!".
(4)Write()方法。功能是把字节切片p写入缓冲区,返回写入的字节数nn。如果nn小于len(p),则同时返回一个错误原因。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) p := []byte("Hello,world!") n, err := w.Write(p) w.Flush() fmt.Println(string(wr.Bytes()), n, err) }
测试结果为:
Hello,world! 12 <nil>
(5)WriteByte()方法。功能是写入一个字节,如果成功写入,error返回nil,否则返回错误原因。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) var c byte = 'G' err := w.WriteByte(c) w.Flush() fmt.Println(string(wr.Bytes()), err) }
测试结果为:
G <nil>
(6)WriteRune()方法。功能是以UTF-8编码写入一个Unicode字符,返回写入的字节数和错误信息。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) var r rune = '中' size, err := w.WriteRune(r) w.Flush() fmt.Println(string(wr.Bytes()), size, err) }
测试结果为:
中 3 <nil>
(7)WriteString()方法。功能是写入一个字符串,并返回写入的字节数和错误信息。如果返回的字节数小于len(s),则同时返回一个错误说明原因。示例如下:
package main import ( "bufio" "bytes" "fmt" ) func main() { wr := bytes.NewBuffer(nil) w := bufio.NewWriter(wr) s := "Hello,world!" n, err := w.WriteString(s) w.Flush() fmt.Println(string(wr.Bytes()), n, err) }
测试结果为:
Hello,world! 12 <nil>