学堂 学堂 学堂公众号手机端

006-统计(三)

lewis 1年前 (2024-04-16) 阅读数 14 #技术


想吐槽了吗?是不是和统计杠上了啊?不是不是,这一节我们要学习一个新的包,以及另一个新的函数。先来说说要干啥。

之前我们从命令行接收文件名后,把文件打开后,直接丢给了 stat 函数去处理,这种方式是以流式来处理文件内容的。其实我们还有一种方法,我们可以一次性将文件内容全部读出来,然后再将读出来的数据按 ​​\n​​ 进行分割。


在 linux 系统接口中,提供了 c 语言接口 ​​open​​​, ​​read​​​ 函数可以帮我们做到,在 go 中,os 包里也提供了 ​​os.Open​​​, ​​os.Read​​ 这些函数,也可以做到。如果真的使用这些函数,有些费劲,因为不管是 c 语言接口还是 go 语言接口,这两个 read 函数都不能保证一次性将文件内容全部读完。

所以,go 语言又提供了另一个非常好用的包 ​​ioutil​​ 包给我们使用。

1. ioutil 包



图1 ioutil 包


可以看到 ​​ioutil​​​ 包提供了一些比较实用的函数,其中有一个是我们想要的,即 ​​ReadFile​​ 函数。我们单独看看此函数的文档。



图2 ReadFile 函数


这份文档非常给力,还提供了一个示例给我们。

​ReadFile​​​ 函数返回一个​​[]byte​​​,它非常像数组,实际上它是一个 ​​byte​​​ 类型的 ​​slice​​​. 没错你又再一次见到了 ​​slice​​​ 类型。回忆一下,前面学过的 ​​slice​​​ 类型的对象是啥?​​os.Args​​​, 它是一个 ​​string​​​ 类型的 ​​slice​​. 不要着急,slice 类型后面一定会非常细致的讲解,在这里,『姑且』认为它就是个数组好了。

2. 程序
package main

import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
)

func main() {
counts := make(map[string]int)

files := os.Args[1:]

if len(files) == 0 {
stat(os.Stdin, counts)
} else {
for _, file := range files {
// 注意了,在使用 ioutil 包的时候,不需要写出完整的包声明路径 io/ioutil,
// 只要写最后一部分就行了
data, err := ioutil.ReadFile(file) // 读取文件内容
if err != nil {
fmt.Fprintf(os.Stderr, "ReadFile:%v\n", err)
continue
}

// string(data) 表示把 []byte 转换成 string 类型的字符串
// strings 包提供了 Split 函数,将字符串进行分割
for _, line := range strings.Split(string(data), "\n") {
counts[line]++
}
}
}

print(counts)
}

func print(counts map[string]int) {
for key, value := range counts {
if value > 1 {
fmt.Printf("%3d %s\n", value, key)
}
}
}

func stat(f *os.File, counts map[string]int) {
inputScanner := bufio.NewScanner(f)

for
3. 分析

关于 ​​ioutil.ReadFile​​​ 函数上面已经介绍过了,但是上面的程序又出现了 ​​srings​​​ 包啊,​​Split​​​ 函数啊,​​string(data)​​ 这些玩意儿,这些东西其实和其它语言都是类似的。

关于 ​​string(data)​​​ 还需要提一嘴,它表示将 ​​[]byte​​​ 类型转换成 ​​string​​​ 类型。非常像 c 语言的类型转换,但是也有点像 ​​C++​​ 的构造函数,好了,我们就不要猜了,好戏都在后面。

4. 总结知道 io/ioutil 包知道 strings 包

练习:

查阅一下​​strings​​ 包里都有哪些函数。使用​​ioutil.ReadFile​​ 函数读取文件内容,并输出到屏幕。


版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门