golang快速入门(三)初尝IO输入输出

zhangxiaohai · · 3198 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

**提示:本系列文章适合对Go有持续冲动的读者** ### 一、关于map与输入方式的窥探 在python 中可以通过字典dict做字符等统计,在go中有类似数据结构map。 **map**存储了键/值(key/value)的集合,对集合元素,提供常数时间的存、取或测试操作。键可以是任意类型,只要其值能用`==`运算符比较,最常见的例子是字符串;值则可以是任意类型。这个例子中的键是字符串,值是整数。 ##### 1.通过标准输入`bufio`包读取数据 ```go package main import ( "bufio" "fmt" "os" ) func main() { counts := make(map[string]int) //创建一个空map input_data := bufio.NewScanner(os.Stdin) for i := 0; i < 5; i++ { input_data.Scan() counts[input_dat a.Text()]++ } for index, value := range counts { //通过range遍历map fmt.Printf("%s\t%d\n", index, value) } } ``` `bufio`包,它使处理输入和输出方便又高效。`Scanner`类型是该包最有用的特性之一,它读取输入并将其拆成行或单词;通常是处理行形式的输入最简单的方法。 **通过range对`map`的迭代顺序是随机的**,这种设计是有意为之的,因为能防止程序依赖特定遍历顺序,这里后续在深入学习。 --- ##### 2. 通过文件读取数据 ```go package main import ( "bufio" "fmt" "os" ) func main() { file := os.Args[1:] counts := make(map[string]int) //创建一个空map if len(file) == 0 { //无有文件参数时调用标准输入函数 countline(counts) //传入counts的copy } else { for _, arg := range file { f, err := os.Open(arg) if err != nil { fmt.Println(os.Stderr) continue } read_file(f, counts) //传入文件和counts的copy } } for index, value := range counts { //打印行和统计数字 fmt.Printf("%s\t%d\n", index, value) //类c语言中的prinf函数 } } //读取文件,传入一个已打开文件、map类型参数counts func read_file(f *os.File, counts map[string]int) { input := bufio.NewScanner(f) for input.Scan() { //Scan搜索文件下一行 counts[input.Text()]++ } } func countline(counts map[string]int) { input_data := bufio.NewScanner(os.Stdin) for i := 0; i < 5; i++ { input_data.Scan() counts[input_data.Text()]++ } } // myfile [root@VM-0-5-centos course2]# cat myfile aaa bbb aaa ccc ddd //output [root@VM-0-5-centos course2]# go run counts.go myfile ddd 1 aaa 2 bbb 1 ccc 1 ``` `map`作为参数传递给某函数时,该函数接收这个引用的一份拷贝(copy,或译为副本),被调用函数对`map`底层数据结构的任何修改,调用者函数都可以通过持有的`map`引用看到。即在上面程序中`read_file`和`countline`对counts这个map做修改后可以被`main`发现,在其他语言中可能需要通过return返回数据,在go就不需要啦。 go中`fmt.Printf`函数提供类c语言中的prinf的输出格式化能力。 ``` %d 十进制整数 %x, %o, %b 十六进制,八进制,二进制整数。 %f, %g, %e 浮点数: 3.141593 3.141592653589793 3.141593e+00 %t 布尔:true或false %c 字符(rune) (Unicode码点) %s 字符串 %q 带双引号的字符串"abc"或带单引号的字符'c' %v 变量的自然形式(natural format) %T 变量的类型 %% 字面上的百分号标志(无操作数) ``` --- ##### 3.通过ReadFile读取文件 `ReadFile`一次性读取所有内容。`ReadFile`函数返回一个**字节**切片(byte slice),必须把它转换为`string`,再通过`strings.Split`分割。 ```go package main import ( "fmt" "io/ioutil" "os" "strings" ) func main() { counts := make(map[string]int) //创建一个空map for _, filename := range os.Args[1:] { data, err := ioutil.ReadFile(filename) if err != nil { fmt.Println(os.Stderr, "%v", err) continue } //fmt.Println(string(data)) for _, line := range strings.Split(string(data), "\n") { if len(line) > 0 { counts[line]++ } } output(counts) } } func output(counts map[string]int) { for index, value := range counts { fmt.Printf("%s\t%d\n", index, value) } } //output [root@VM-0-5-centos course2]# go run ioutil.go myfile aaa 2 bbb 1 ccc 1 ddd 1 ``` 实现上,`bufio.Scanner`、`ioutil.ReadFile`和`ioutil.WriteFile`都使用`*os.File`的`Read`和`Write`方法,但是,大多数程序员很少需要直接调用那些低级(lower-level)函数。高级(higher-level)函数,像`bufio`和`io/ioutil`包中所提供的那些,用起来要容易点。 --- ### 二、 练习 **练习 1.4:** 修改code,出现重复的行时打印文件名称。 调整output函数如下即可。 ```go func output(counts map[string]int) { for index, value := range counts { if value >=2{ fmt.Printf("filename:%s %s\t%d\n", os.Args[0],index, value) }else{ fmt.Printf("%s\t%d\n", index, value) } } } //output [root@VM-0-5-centos course2]# go run ioutil.go myfile bbb 1 ccc 1 ddd 1 filename:/tmp/go-build303515636/b001/exe/ioutil aaa 2 ``` --- 公众号【容器云实践】 [golang快速入门(三)初尝IO输入输出](https://mp.weixin.qq.com/s?__biz=MzkzNjEwNTMyNA==&mid=2247483661&idx=1&sn=b3fab5c19b1c6114efa7ef56b11a2371&chksm=c2a2850ef5d50c18153aa284d340bc8400448d13c0a863c97b4156593691846fc7764d1de937&token=1931167070&lang=zh_CN#rd)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3198 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传