上次我们从命令行接收用户输入,并统计了每次输入内容出现的次数,今天对程序加以改造,使其能够读取文件内容,并统计每行文本出现的次数。
首先,我们把接收输入的逻辑封装成一个函数:
// scan.go
package main
import (
"os"
"fmt"
"bufio"
)
func main() {
counts := make(map[string]int)
fmt.Printf("Please type in something:\n")
countLines(os.Stdin, counts)
for line, n := range counts {
fmt.Printf("%d : %s\n", n, line)
}
}
// 统计行数
func countLines(file *os.File, counts map[string]int) {
input := bufio.NewScanner(file)
for input.Scan() {
line := input.Text()
if line == "bye" {
break
}
counts[line]++
}
}
上面的 coutLines
函数有两个参数:file *os.File
和 counts map[string]int
,第一个参数可以接收标准输入或文件对象,第二个参数接收一个 map 引用。
然后,我们移除接收命令行输入的逻辑,替换为读取当前目录下的 test.txt
文件:
// scan.go
package main
import (
"os"
"fmt"
"bufio"
)
func main() {
counts := make(map[string]int)
// 打开文件
file, err := os.Open("test.txt")
// 异常处理
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
countLines(file, counts)
// 关闭文件
file.Close()
for line, n := range counts {
fmt.Printf("%d : %s\n", n, line)
}
}
// 统计行数
func countLines(file *os.File, counts map[string]int) {
input := bufio.NewScanner(file)
for input.Scan() {
counts[input.Text()]++
}
}
我们使用 os.Open
打开 test.txt
文件,如果出现异常,则进行异常处理,如果读取成功,则统计内容,最后关闭文件。
test.txt
文件内容如下:
hello
world
hello
下面是程序的运行结果:
$ go run scan.go
# 输出内容
2 : hello
1 : world
除上述方式之外,我们还可以使用 io/ioutil
中的方法来读取文件,然后以换行符分割进行统计,实现代码如下:
// split.go
package main
import (
"os"
"fmt"
"strings"
"io/ioutil"
)
func main() {
counts := make(map[string]int)
// 读取文件
data, err := ioutil.ReadFile("test.txt")
// 异常处理
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
// 将数据转换为字符串 然后以换行符分割
lines := strings.Split(string(data), "\n")
for _, line := range lines {
counts[line]++
}
for line, n := range counts {
fmt.Printf("%d : %s\n", n, line)
}
}