一个Go语言按行读取文件的脚本

脚本内容

假设我有一个文件111.txt,内容如下:
akb48

现在需要读取这个111.txt,并将文件里的数值,然后组合成一个数列,再写入到222.txt里。写了一个go脚本flagtest.go,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package main

import (
"bufio"
"flag"
"fmt"
"io"
"os"
"strconv"
)

var infile *string = flag.String("i","infile","file contains vales for sorting") //flag 包中,定义的指令以指针类型返回
var outfile *string = flag.String("o","outfile","file to receive sorted values")

func readValues(infile string)(values []int,err error){
file, err := os.Open(infile)
if err != nil{
fmt.Println("failed to open this file:",infile)
return
}

defer file.Close() //资源释放,关闭文件句柄
//file.Close()不会触发panic,会先判断file == nil
//defer 除了最后执行之外还有一个重要的特性:即便函数抛出了异常,也会被执行的。 这样就不会因程序出现了错误,而导致资源不会释放了

br := bufio.NewReader(file) //读缓冲区

values = make([]int,0) //空切片

for {
line,isPrefix,err1 := br.ReadLine()

if err1 != nil{
if err1 != io.EOF {
err = err1
}
break
}

if isPrefix {
fmt.Println("A too long line,seems unexpected.")
return
}

str := string(line) //转换字符数组成字符串

value,err1 := strconv.Atoi(str)

if err1 != nil {
err = err1
return
}

values = append(values,value)

}
fmt.Println(values)
return
}

func writeVaules(values []int, outfile string) error{
file, err := os.Create(outfile)
if err != nil{
fmt.Println("创建文件失败!",outfile)
return err
}

defer file.Close()

for _,value := range values { //第一个是下标,第二个是元素
str := strconv.Itoa(value) //int到string
file.WriteString(str + "\n") //如果是windows文件,那就是\r\n
}
return nil
}


func main(){
flag.Parse()
if infile != nil{
fmt.Println("infile =",*infile,"outfile =",*outfile)
}
values,err := readValues(*infile)
if err == nil{
fmt.Println("原文件的内容是:", values)
fmt.Println("现在开始录入到新文件里...")
writeVaules(values, *outfile)
} else {
fmt.Println(err)
}
}

执行效果如下:
akb48

新的知识点!

  1. bufio.NewReader的返回值里lineerr不可能同时非nil
  2. string方法会自动识别\n和\t等通配符。
  3. reader.ReadBytes("\n")这个方法可以将字符串按\n分割,然后取第一部分。
  4. 读取一行,通常会选择ReadBytesReadString。不过,正常人的思维,应该用ReadLine,只是不明白为啥ReadLine的实现不是通过ReadBytes,然后清除掉行尾的\n(或\r\n),它现在的实现,用不好会出现意想不到的问题,比如丢数据。个人建议可以这么实现读取一行:
    1
    2
    line, err := reader.ReadBytes('\n')
    line := bytes.TrimRight(line, "\r\n")

这样既读取了一行,也去掉了行尾结束符(当然,如果你希望留下行尾结束符,只用ReadBytes即可)。

参考资料

https://segmentfault.com/a/1190000014935402
http://qefee.com/2014/02/02/go%E8%AF%AD%E8%A8%80%E7%9A%84flag%E5%8C%85%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/ (flag各种用法集合)
http://fuxiaohei.me/2015/12/9/mistake-in-bufio-reader.html (bufio.reader的坑)
https://github.com/ma6174/blog/issues/10 (bufio.reader的坑2)
https://studygolang.com/articles/5932 (go使用Defer的几个场景)

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------