文件读取
1. 学习内容
- 把整个文件读进内存
- 使用文件的绝对路径
- 文件路径作为命令行参数传递
- 将文件绑定到二进制文件中
- 一小块一小块地读取文件
- 一行一行地读取文件
2.把整个文件读进内存
最基本的文件操作就是把整个文件读进内存中。
- 使用ioutil包下的ReadFile函数即可完成
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("./test.txt")
if err != nil {
fmt.Println("File reading error: ", err)
return
}
fmt.Println(data) // 读取到文件内容的字符串ASC码构成的切片[97 115 100 115 97 100 97 115 100 97 115 100]
fmt.Println(string(data)) // 将字符串切片转成字符串
}
- 因为 Go 是编译型语言。go install 会根据源代码创建一个二进制文件。二进制文件独立于源代码,可以在任何位置上运行。由于在运行二进制文件的位置上没有找到 test.txt,因此程序会报错,提示无法找到指定的文件。这是相对于二进制文件的路径。
- 有三种方法可以解决这个问题
- 使用绝对文件路径
- 将文件路径作为命令行标志传递
- 将文件绑定在二进制文件中
- 有三种方法可以解决这个问题
2.1 使用绝对文件路径
绝对路径的话,可以在文件任何位置运行
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("E:/奋战2021/1.go语言体系/1.Google资深工程师深度讲解Go语言/code/test.txt")
if err != nil {
fmt.Println("File reading error: ", err)
return
}
fmt.Println(data) // 读取到文件内容的字符串ASC码构成的切片[97 115 100 115 97 100 97 115 100 97 115 100]
fmt.Println(string(data)) // 将字符串切片转成字符串
}
2.2 将文件路径作为命令行标志传递
- 要借助以下几样东西:
- flag包
- flag包具有的一个String函数,即flag.String(标记的名称,标记的默认值,标记的剪短描述)
- 返回值就是
- flag.Parse()
- 在程度访问flag之前,都必须调用flag.Parse()
- 举例:
import (
"fmt"
"flag"
)
func main() {
fptr := flag.String("fpath", "test.txt", "descval") // 代表将"test.txt"给这个标志"flag",返回标志的值对应的地址,默认即存储"test.txt"的地址
flag.Parse()
fmt.Println(*fptr) // 取地址对应的值"test.txt"
}
- 然后go build产生exe文件
- 然后使用如下命令,就会将/文件夹路径/test.txt赋值给fpath(fpath默认值是"test.txt"),/文件夹路径/是当前文件夹绝对路径
./exe文件 -fpath=/文件夹路径/test.txt
-
所以如果上面这段代码,执行了上面的命令,则打印的*fptr不再是默认值,而是文件test.txt的绝对路径
-
完整命令行读取文件的代码及命令
import (
"fmt"
"flag"
"io/ioutil"
)
func main() {
fptr := flag.String("fpath", "test.txt", "descval") // 代表将"test.txt"给这个标志"flag",返回标志的值对应的地址,默认即存储"test.txt"的地址
flag.Parse()
data, err := ioutil.ReadFile(*fptr)
if err != nil {
fmt.Println("Read file error: ", err)
return
}
fmt.Println(string(data)) // 返回文件内容
}
执行命令: ./code.exe -fpath=/e/奋战2021/1.go语言体系/1.Google资深工程师深度讲解Go语言/code/test.txt
2.3 将文件绑定在二进制文件中-----这块还不是很懂!!!!!!!!!!!!!
- 步骤:
- 安装paker包
go get -u github.com/gobuffalo/packr (具体地址再百度下)
- 写执行程序
package main import ( "fmt" "github.com/gobuffalo/packr" // 引入packr包 ) func main() { box := packr.NewBox("../code") // 创建一个box,这个box代表一个文件夹,文件夹中的内容会被嵌入到二进制文件中 data := box.String("test.txt") // 读取box中test.txt文件的内容 fmt.Println("Contents of file:", data) }
- 创建二进制文件
go build
- 会产生code.exe
- 执行code.exe
./code.exe
- 即会执行上面的代码,打印出文件内容
3.一小块一小块的读取文件
当文件内容很大时,不能一次性读取到内存中,这时候可以考虑一小块一小块读取
- 举例:以3字节的块一块一块读取文件test.txt
package main
import (
"fmt"
"flag"
"os"
"log"
"bufio"
)
func main() {
// 首先用命令行中接收文件路径,文件路径就是*filePoint
filePoint := flag.String("filePath", "test.txt", "readFile")
flag.Parse()
f, err := os.Open(*filePoint) // 打开文件
if err != nil { // 错误处理
log.Fatal(err)
}
defer func(){ // 延迟处理,延迟文件的关闭,这样读完就会关闭
if err = f.Close(); err !=nil {
log.Fatal(err)
}
}()
// 创建一个缓冲区reader
r := bufio.NewReader(f)
b := make([]byte, 3) // 创建一个3字节的切片,每次读取都存在这个切片中
for {
n, err := r.Read(b) // 按照切片的长度去读取(读之前清空b),也就是每次读3个字节,并存到b中,返回读取的长度
if err != nil { // 错误处理,一旦读完,就是返回一个EOF错误
fmt.Println("Error reading file: ", err)
break
}
fmt.Println(string(b[0:n])) // 打印出每次读取的内容转成字符串,注意中文可能会有问题,三个字符可能会出现不是完整的汉字
}
}
4.一行一行的读取文件
package main
import (
"fmt"
"flag"
"os"
"log"
"bufio"
)
func main() {
// 首先用命令行中接收文件路径,文件路径就是*filePoint,是相对路径
filePoint := flag.String("filePath", "test.txt", "readFile")
flag.Parse()
f, err := os.Open(*filePoint) // 打开文件
if err != nil { // 错误处理
log.Fatal(err)
}
defer func(){ // 延迟处理,延迟文件的关闭,这样读完就会关闭
if err = f.Close(); err !=nil {
log.Fatal(err)
}
}()
// 创建一个scabber
s := bufio.NewScanner(f)
for s.Scan() { // 扫描每一行,如果存在,则打印
fmt.Println(s.Text()) // 转成字符串
}
err = s.Err() // 监听错误
if err != nil {
log.Fatal(err)
}
}