go入门练习002:查找重复的行
读取标准输入
go的标准输入是os.Stdin,可以用bufio包下的 Scanner来读取。Scanner的Scan()方法每次读取一行,去掉结尾的换行符,然后可以用Text()方法获取这一行。
标准输入结束的默认动作是ctrl+C,这时Scan()方法没有扫描到输入行,返回false。
下面程序,从标准输入一行一行读取数据,并打印出重复的行及其重复次数:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
counts[input.Text()]++
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
读取文件:流(streaming)模式
标准输入本质也是文件,只不过不需要显示调用os.Open()打开。os.Open()有两个返回值,第一个是打开的文件,第二个是错误。如果打开文件时报错,错误信息在第二个返回值里,可以用nil判断。
func main() {
counts := make(map[string]int)
files := os.Args[1:]
if len(files) == 0 {
countLines(os.Stdin, counts)
} else {
for _, arg := range files {
f, err := os.Open(arg)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
continue
}
countLines(f, counts)
f.Close()
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
func countLines(f *os.File, counts map[string]int) {
input := bufio.NewScanner(f)
for input.Scan() {
counts[input.Text()]++
}
}
读取文件:非流模式
流模式根据需要不断地从输入流中读取数据,可以无限读下去。非流模式则一次把文件读取到内存,然后再进行相应的操作。
可以用io/ioutil包下的ReadFile函数读取文件数据到内存,然后用string构造函数转为字符串,最后用strings包Split分割成子字符串组成的切片。
func main() {
counts := make(map[string]int)
for _, filename := range os.Args[1:] {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
continue
}
for _, line := range strings.Split(string(data), "\n") {
counts[line]++
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}