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)
		}
	}
}

posted on 2020-10-21 11:20  caffebabe  阅读(154)  评论(0编辑  收藏  举报