本文提供常见的两种输入方式(文本输入和终端输入)的处理样例代码。
1.1 普通文件读取
- 普通文件的读取可使用os.Open()或os.OpenFile(),组合bufio.NewReader()或bufio.NewScanner()逐行读取数据。
os.Open()和os.OpenFile()的区别:
//仅读取文件,O_RDONLY
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
//flag可设置不同的文件模式及perm,文件可用于正常IO读写
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
return openFileNolog(name, flag, perm)
}
bufio.NewReader()或bufio.NewScanner()区别
均可用于文件读写。以下样例中ReadLine及Scan默认以换行符"\n"分行读取
file, _ := os.Open(filePath)
reader := bufio.NewReader(file)
for {
result, _, _ := reader.ReadLine()
fmt.Println(result)//输出到标准输出
}
/********或**********/
input := bufio.NewScanner(file)//初始化一个扫表对象
for {
if input.Scan() {//扫描输入内容
line := input.Text()//把输入内容转换为字符串
fmt.Println(line)//输出到标准输出
}
}
其中scanner提供灵活的文本分隔方法,用于使用更方便,具体可参照2.1中scanner.Split方法的介绍。
1.2 配置文件读取
常用的配置文件格式有toml、json和conf三种。
- toml文件读取,依赖"github.com/BurntSushi/toml"包解析数据
/**************conf.toml内容为******************/
[hostInfo]
Warehouse = "GZ-HL"
Host = "10.96.66.19"
/**************配置解析函数为******************/
type HostInfo struct {
Host string `toml:"Host"`
Warehouse string `toml:"Warehouse"`
}
type Config struct {
HostConf HostInfo `toml:"hostInfo"`
}
var Conf Config
func InitConf() error {
file, err := os.OpenFile("./conf/conf.toml", os.O_RDWR, 0666)
if err != nil {
log.Panic(err.Error())
return err
}
content, err := ioutil.ReadAll(file)
if err != nil {
log.Panic(err.Error())
return err
}
_, err = toml.Decode(string(content), &Conf)
if err != nil {
log.Panic(err.Error())
return err
}
return nil
}
- json文件读取,依赖"encoding/json"包解析数据
/**************conf.toml内容为******************/
{
"hostInfo":{
"warehuose":"GZ-HL",
"host":"10.96.66.19"
}
}
/**************配置解析函数为******************/
type HostInfo struct {
Host string `json:"host"`
Warehouse string `json:"warehouse"`
}
type Config struct {
HostConf HostInfo `json:"hostInfo"`
}
var Conf Config
func InitConf() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
file, err := os.OpenFile("./conf/conf.json", os.O_RDWR, 0666)
if err != nil {
log.Panic(err.Error())
}
content, err := ioutil.ReadAll(file)
if err != nil {
log.Panic(err.Error())
}
err = json.Unmarshal(content, &Conf)
if err != nil {
log.Panic(err.Error())
}
}
- conf文件读取,依赖"github.com/astaxie/beego/config"包解析数
/**************conf.conf内容为******************/
[hostInfo]
warehouse = "GZ-HL"
host = "10.96.66.19"
/**************配置解析函数为******************/
func main(){
ConfPath := flag.String("c", "./conf/app.conf", "config file.")
flag.Parse()
conf, err = config.NewConfig("ini", *ConfPath)
warehouse := strings.ToLower(conf.String("hostInfo::warehouse"))
host := strings.ToLower(conf.String("hostInfo::host"))
}
json、toml和conf文件格式的配置文件均可满足用户需求,json层次清晰,配置文件中不可添加注释。toml轻量,可添加注释。conf文件解析无需定义struct格式。
二、命令行输入2.1 bufio包参数解析
- bufio用于标准输入读取。其中bufio.Reader及bufio.Scanner均可实现输入读取。bufio.Scanner用于文本扫描&缓存&自定义匹配函数,bufio.Reader对于文本处理,需考虑处理行太长问题。二者底层均依赖io.Reader(bytes,strings)
package main
import (
"bufio"
"fmt"
"os"
)
func main(){
reader := bufio.NewReader(os.Stdin)
for {
result,_,_ := reader.ReadLine()
fmt.Println("this line is : ", result)
}
}
/********或**********/
func main(){
input := bufio.NewScanner(os.Stdin)//初始化一个扫表对象,os.stdin读取linux下文件/dev/stdin
for {
if input.Scan() {//扫描输入内容
line := input.Text()//把输入内容转换为字符串
fmt.Println("this line is : ", line)//输出到标准输出
}
}
}
输入输出:
hello
this line is : hello
Scanner.Scan方法默认以换行符\n作为分隔符号。Go语言还提供四种方法,ScanBytes返回单个字节作为一个token,ScanWords通过空格分隔单词,ScanRunes返回单个UTF-8编码的rune作为一个token,ScanLines返回一行文本,换行以\n或windows下\r\n为依据。
/********ScanWords样例**********/
scanner := bufio.NewScanner(strings.NewReader("hello world !"))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
输出:
hello
world
!
/********ScanLines样例**********/
scanner := bufio.NewScanner(strings.NewReader("hello world \n!"))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
输出:
hello world
!
同时可自定义分隔方法splitFunc,下面给出一个自定义以字符"Golang"为切割的自定义splitFunc。
package main
import (
"bufio"
"bytes"
"strings"
"fmt"
)
func main() {
const inputstr = "This is The Golang Standard Library.\nWelcome you!"
input := bufio.NewScanner(strings.NewReader(inputstr))
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
if j := bytes.IndexAny(data, "Golang"); j >0{
return j, data[:j], nil
}
if atEOF {
return 0, data, bufio.ErrFinalToken
} else {
return 0, nil, nil
}
}
input.Split(split)
for {
if input.Scan() {//扫描输入内容
line := input.Text()//把输入内容转换为字符串
fmt.Println(line)//输出到标准输出
}
}
}
输出
This is The
Golang Standard Library.
Welcome you!
对于简单的读取一行数据,并灵活分隔数据,我们采用Scanner而不是Reader
2.2 os包参数解析
- Go的命令行参数存储在切片 os.Args,其中第一个参数为可执行文件的名字,其他的参数都是以字符串的形式,存储在slice os.Args当中,可以通过for range 语句来遍历所有的参数。下面是一个例子。
//编译后可执行文件名为paramRead
package main
import (
"fmt"
"os"
)
func main(){
if len(os.Args)!=0{
//遍历打印slice os.Args中参数
for i, args := range os.Args{
fmt.Printf("arg[%d]:%s\n",i,args)
}
}
}
$ ./paramRead 5 3 1 //输入参数5 3 1
arg[0]:./paramRead //第一个参数为可执行文件名称
arg[1]:5 //第二个参数
arg[2]:3 //第三个参数
arg[3]:1 //第四个参数
2.3 flag包参数解析
- os包参数解析只是把命令行中参数存储在os.Args切片当中,对于需输入多维度参数的可执行文件的使用,可使用golang内置的flag包对参数进行说明,并可设置默认值。
- flag包的使用方法有两种
flag.Type(name string,defaultvalue Type, helpMsg string) *Type
或
flag.TypeVar(目标参数*Type, name string, value Type, usage string)
- flag包依据Type的类型、参数标志name,对标志name设置默认值和帮助信息,最终返回一个指向该类型的指针,可通过指针是否为空来判断命令行里是否使用该标志参数,下面是一个例子
//编译后可执行文件名为paramRead
package main
import (
"flag"
"fmt"
)
var addr string
var hostname = flag.String("name", "hello","localhost name")//参数名为hostname,默认配置为hello,注释为localhost name
func main(){
flag.StringVar(&addr, "addr", "127.0.0.1","localhost ip addr")//参数名为addr,默认配置为127.0.0.1,注释为localhost ip addr
flag.Parse()
fmt.Println("addr: ", addr)
fmt.Println("hostname: ", *hostname)
}
- 命令行执行./paramRead -help,可看到设置的参数帮助信息
$ ./paramRead -help
Usage of ./paramRead:
-addr string
localhost ip addr (default "127.0.0.1")
-name string
localhost name (default "hello")
- 命令行参数输入./paramRead -addr 172.25.5.0,对localaddr进行配置,发现addr显示为172.25.5.0,name走默认配置为hello
$ ./paramRead -addr 172.25.5.0
addr: 172.25.5.0
name: hello
2.4 fmt包参数解析
fmt包中提供fmt.Scan(以空格作为参数分隔符),调用Scan函数时,需指定接收输入的变量名和变量数,直到接收完所有指定的变量数,Scan函数才会返回,回车符也无法提前让它返回。以下给出一个样例。
package main
import "fmt"
func main() {
fmt.Println("Please enter the firstParam and secondParam: ")
var firstParam, secondParam string
fmt.Scan(&firstParam, &secondParam)
fmt.Printf("firstParam is %s, secondParam is %s\n", firstParam, secondParam)
}
输入输出:
Please enter the firstParam and secondParam:
hello
world
firstParam is hello, secondParam is world
总结:
- 文件的读取:普通文件采用os.Open或os.OpenFile及bufio.Reader或bufio.Scanner组合,项目中配置文件介绍了.json、.toml及.conf格式,采用os.Open与ioutil.ReadAll组合方式。
- 终端输入读取:os.Args、bufio、flag及fmt均可满足需求
参考链接:[golang学习链接]https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter01/01.4.html