课程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主讲老师 Matt Holiday
07-Formatted & File I/O
I/O steams
操作系统具有三个标准 io 流,标准输入、标准输出、标准错误。它们分别可以重定向。
formatted I/O
Println
将参数默认输出到标准输出流,如果会用 Fprintln
可以指定输出到某个流,比如 os.Stderr
fmt functions
Sprintln
格式化字符串并返回。
package main
import \"fmt\"
func main() {
a, b := 12, 345
c, d := 1.2, 3.45
fmt.Printf(\"%d %d\\n\", a, b)
fmt.Printf(\"%x %x\\n\", a, b)
fmt.Printf(\"%#x %#x\\n\", a, b)
fmt.Printf(\"%f %.2f\", c, d)
fmt.Println()
fmt.Printf(\"|%6d|%6d|\\n\", a, b)
fmt.Printf(\"|%-6d|%-6d|\\n\", a, b)
fmt.Printf(\"|%06d|%06d|\\n\", a, b)
fmt.Printf(\"|%9f|%9.2f|\\n\", c, d) // ^ 当数字过大时也会超出
}
12 345
c 159
0xc 0x159
1.200000 3.45
| 12| 345|
|12 |345 |
|000012|000345|
| 1.200000| 3.45|
package main
import (
\"fmt\"
)
func main() {
s := []int{1, 2, 3}
a := [3]rune{\'a\', \'b\', \'c\'}
m := map[string]int{\"and\": 1, \"or\": 2}
ss := \"a string\"
b := []byte(ss)
fmt.Printf(\"%T\\n\", s)
fmt.Printf(\"%v\\n\", s)
fmt.Printf(\"%#v\\n\", s) // ^ %#v 更符合初始化时输入的形式
fmt.Println()
fmt.Printf(\"%T\\n\", a)
fmt.Printf(\"%v\\n\", a)
fmt.Printf(\"%q\\n\", a) // ^ 注意这个%q将rune从int32转化成了字符串
fmt.Printf(\"%#v\\n\", a)
fmt.Println()
fmt.Printf(\"%T\\n\", m)
fmt.Printf(\"%v\\n\", m)
fmt.Printf(\"%#v\\n\", m)
fmt.Println()
fmt.Printf(\"%T\\n\", ss)
fmt.Printf(\"%v\\n\", ss)
fmt.Printf(\"%q\\n\", ss)
fmt.Printf(\"%#v\\n\", ss)
fmt.Printf(\"%v\\n\", b)
fmt.Printf(\"%v\\n\", string(b)) // ^ 将字节切片转换为字符串
}
[]int
[1 2 3]
[]int{1, 2, 3}
[3]int32
[97 98 99]
[\'a\' \'b\' \'c\']
[3]int32{97, 98, 99}
map[string]int
map[and:1 or:2]
map[string]int{\"and\":1, \"or\":2}
string
a string
\"a string\"
\"a string\"
[97 32 115 116 114 105 110 103]
a string
file I/O
Practice ① I/O
编写一个类似 Unix cat 的程序,将多个文件输出到标准输出流中,并输出为一个文件。
package main
import (
\"fmt\"
\"io\"
\"os\"
)
func main() {
for _, fname := range os.Args[1:] {
file, err := os.Open(fname)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
if _, err := io.Copy(os.Stdout, file); err != nil {
fmt.Fprint(os.Stderr, err)
continue
}
fmt.Fprint(os.Stdout, \"\\n\") // ^ 每个文件内容末尾添加换行符
file.Close()
}
}
io.copy
是一个很棒的功能,它知道如何缓冲、如何以块的形式读入并写会,它不会尝试把整个文件读取到内存中也不会一次读取一个字符。
file.Close
大多数操作系统对程序中打开多少个文件有限制,所以文件使用完成后需要进行关闭。
在当前目录新建 txt
文件,写入内容。执行下面三条命令。
go run . a.txt
go run . a.txt b.txt c.txt
go run . a.txt b.txt c.txt > new.txt
第二条指令结果
[]int{1, 2, 3}
go go go
people car
cat
apple
banana
第三条指令在当前目录生成了 new.txt 文件,内容是 标准输出流 的内容。
Always check the err
Practice ② I/O
编写一个简短的程序计算文件大小。一次性读取(小文件情况下)
我们前面知道, io/ioutil
包可以对整个文件进行读取,存入内存中。我们可以使用它计算文件大小。
原先的 io.Copy
返回的是复制的字节数,而 ReadAll
将返回整个 data
,字节切片和一个err。
package main
import (
\"fmt\"
\"io/ioutil\"
\"os\"
)
func main() {
for _, fname := range os.Args[1:] {
file, err := os.Open(fname)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Fprint(os.Stderr, err)
continue
}
fmt.Println(\"The file has\", len(data), \"bytes\")
file.Close()
}
}
go run . a.txt b.txt c.txt
The file has 30 bytes
The file has 20 bytes
The file has 18 bytes
data, err := ioutil.ReadAll(file)
从 if
中取出单独成行,是因为需要 data
这个变量。如果放在 if
短声明里会导致作用域只在 if
语句块内。
Practice ③ I/O
编写一个 wc 程序(word counter),输出lines、words、characters数量。使用缓冲 buffio(大文件情况下)
package main
import (
\"bufio\"
\"fmt\"
\"os\"
\"strings\"
)
func main() {
for _, fname := range os.Args[1:] {
var lc, wc, cc int
file, err := os.Open(fname)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
scan := bufio.NewScanner(file)
for scan.Scan() {
s := scan.Text()
wc += len(strings.Fields(s)) // ^ 根据空格、制表符分割 a slice of words
cc += len(s)
lc++
}
fmt.Printf(\"%7d %7d %7d %s\\n\", lc, wc, cc, fname)
file.Close()
}
}
go run . a.txt b.txt c.txt
3 7 26 a.txt
2 5 18 b.txt
3 3 14 c.txt
bufio.NewScanner(file)
创建一个扫描器按行扫描。考虑到多行需要用 for
循环 scan.Scan
。
strings.Fields(s)
根据空格、制表符分割,拿到的是字符串切片。
来源:https://www.cnblogs.com/linxiaoxu/p/16098735.html
本站部分图文来源于网络,如有侵权请联系删除。