在日常开发中我们少不了对文件读取,今天我们就从三部分来讲解:全量读,带缓冲区读,任意位置读。
我们先来看看一个简单的例子:
package main import ( "fmt" "io/ioutil" ) func main() { dat, err := ioutil.ReadFile("./main.go") fmt.Println(err) fmt.Println(string(dat)) }
运行程序可以打印整个 main.go 文件内容,如果我们将 ./main.go 修改为 ./main.go1,程序将出现 no such file or directory 的错误, 所以在文件读取的时候一定要注意检查 err。
main.go
./main.go
./main.go1
no such file or directory
package main import ( "fmt" "os" ) func main() { f, _ := os.Open("./main.go") defer f.Close() buf := make([]byte, 16) f.Read(buf) fmt.Println(string(buf)) }
运行程序会输出 main.go 的前 16 个字节内容,具体为:
package main im
有些时候我们想在一个文件特定地方读取特定长度的内容,那我们有什么方法可以使用呢?
第一种: f.Seek + f.Read
package main import ( "fmt" "os" ) func main() { f, _ := os.Open("./main.go") defer f.Close() b1 := make([]byte, 2) f.Seek(5, 0) f.Read(b1) fmt.Println(string(b1)) }
运行代码输出结果为:
ge
第二种:使用 f.ReadAt
f.ReadAt
package main import ( "fmt" "os" ) func main() { f, _ := os.Open("./main.go") defer f.Close() b1 := make([]byte, 2) f.ReadAt(b1, 5) fmt.Println(string(b1)) }
运行结果同样为:
但注意:
第一种方式是非并发安全的,例如:
package main import ( "fmt" "os" "time" ) func main() { f, _ := os.Open("./main.go") defer f.Close() for i := 0; i < 5; i++ { go func() { b1 := make([]byte, 2) f.Seek(5, 0) f.Read(b1) fmt.Println(string(b1)) f.Seek(2, 0) f.Read(b1) fmt.Println(string(b1)) }() } time.Sleep(time.Second) }
输出结果为:
ge ge ge ck ck ai ck m ck ck
第二种 f.ReadAt 是并发安全的,例如:
package main import ( "fmt" "os" "time" ) func main() { f, _ := os.Open("./main.go") defer f.Close() for i := 0; i < 5; i++ { go func() { b1 := make([]byte, 2) f.ReadAt(b1, 5) fmt.Println(string(b1)) f.ReadAt(b1, 2) fmt.Println(string(b1)) }() } time.Sleep(time.Second) }
ge ge ck ck ge ge ck ck ge ck
实战项目一: 如何使用 buf 实现 ioutil.ReadFile 类似效果:
buf
ioutil.ReadFile
package main import ( "fmt" "io" "os" ) func main() { f, _ := os.Open("./main.go") defer f.Close() content := make([]byte, 0) buf := make([]byte, 16) for { n, err := f.Read(buf) if err == io.EOF { break } if n == 16 { content = append(content, buf...) } else { content = append(content, buf[0:n]...) } } fmt.Println(string(content)) }
实战项目二: 使用 bufio 实现行统计:
bufio
package main import ( "bufio" "fmt" "io" "os" ) func main() { f, _ := os.Open("./main.go") defer f.Close() br := bufio.NewReader(f) totalLine := 0 for { _, isPrefix, err := br.ReadLine() if !isPrefix { totalLine += 1 } if err == io.EOF { break } } fmt.Println("total lines is:", totalLine) }
运行结果为:
total lines is: 31
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8