服务计算作业3----------使用 golang 开发 selpg

实验目的

使用 golang 开发 开发 Linux 命令行实用程序 中的 selpg

提示:

  1. 请按文档使用 selpg 章节要求测试你的程序
  2. 请使用 pflag 替代 goflag 以满足 Unix 命令行规范, 参考:Golang之使用Flag和Pflag
  3. golang 文件读写、读环境变量,请自己查 os 包
  4. “-dXXX” 实现,请自己查 os/exec 库,例如案例 Command,管理子进程的标准输入和输出通常使用 io.Pipe,具体案例见 Pipe

实验预备

1. 学习pflag包

Golang官方的命令行参数解析库flag,已经用的比较少。而是Google的一位Golang大牛Steve Francia自己写的命令行参数解析库pflag更加优秀,从而得到广泛使用。
服务计算作业3----------使用 golang 开发 selpg

根据pflag作者的说法,pflag是golang的原生falg包的直接替代品,如果您在之前使用flag包的情况下导入pflag,则所有代码可以继续运行而不用进行任何更改.

安装和导入pflag

使用 go get命令就可以安装pflag包

go get github.com/spf13/pflag

使用go test 测试是否安装成功

go test github.com/spf13/pflag

在代码内导入pfalg

import "github.com/spf13/pflag"

了解使用pflag

flag和pflag都是源自于Google,工作原理甚至代码实现基本上都是一样的。 flag虽然是Golang官方的命令行参数解析库,但是pflag却得到更加广泛的应用。 因为pflag相对flag有如下优势:

  • 支持更加精细的参数类型:例如,flag只支持uint和uint64,而pflag额外支持uint8、uint16、int32。
  • 支持更多参数类型:ip、ip mask、ip net、count、以及所有类型的slice类型,例如string slice、int slice、ip slice等。
  • 兼容标准flag库的Flag和FlagSet。
  • 原生支持更丰富flag功能:shorthand、deprecated、hidden等高级功能。

所以pflag的使用与flag基本是相同的:

1. 定义flags

  • 将flag绑定到一个变量* 将flag绑定到一个变量
    import "flag"
    var flagvar int
    func init() {
    	flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
    }
    
  • 相比起来,pflag可以在绑定时直接绑定shorthand
    import "github.com/spf13/pflag"
    // func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string)
    // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash.
    var flagvar int
    pflag.IntVarP(&flagvar, "flagname", "f", 1234, "help message for flagname")
    
  • 还有其他定义方式
    • pfalg
      // func IntP(name, shorthand string, value int, usage string) *int
      // IntP is like Int, but accepts a shorthand letter that can be used after a single dash.
      var ip= pflag.IntP("flagname", "f", 1234, "help message for flagname")
      
    • flag
      import "flag"
      // 返回的是 指针
      var ip = flag.Int("flagname", 1234, "help message for flagname")
      

2. 解析Flag

定义命令行参数之后,和使用命令行参数之前,必须调用pflag.Parse()来解析命令行参数。pflag.Parse()使CommandLine解析除命令行除第一个参数外的所有参数.

// Parse parses the command-line flags from os.Args[1:].  Must be called
// after all flags are defined and before flags are accessed by the program.
func Parse() {
	// Ignore errors; CommandLine is set for ExitOnError.
	CommandLine.Parse(os.Args[1:])
}

2. 学习文件读写

因为此次作业要求要进行文件的按行和按页读取,根据Google的结果来看最好的方法应该是使用package bufio所以接下来我们要学习使用package bufio
bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象

1. 导入bufio包

import "bufio"

2.按行读取

通过阅读文档我发现了一个ReadLine的函数,似乎可以直接使用,但是文档表示不推荐
服务计算作业3----------使用 golang 开发 selpg

既然如此我们采用文档推荐的ReadString(’\n’)
服务计算作业3----------使用 golang 开发 selpg

具体方法如下:

package main
import (
	"os"
	"bufio"
)
func main(){
	fin, err = os.Open(fileName)		//打开文件,默认为只读
	if err != nil { 		//打开出错
		fmt.Fprintf(os.Stdout, "can not open the file\"%s\"\n", fileName)
		fmt.Println(err)
		os.Exit(1)
	}
	defer fin.Close() //结束后关闭文件
	//func NewReader(rd io.Reader) *Reader
	//NewReader创建一个具有默认大小缓冲、从r读取的*Reader
	//Reader实现了给一个io.Reader接口对象附加缓冲
	reader := bufio.NewReader(fin)
	line , lerr := lreader.ReadString('\n') 
	//如此line就为读到的一行数据
}

3. 按页读取

同上理,按页可以使用ReadString(’\f’)但是这会让读到的数据保留'\f'字符,而'\f'字符
会在标准输出到命令行时,可能会产生如同水平制表符的效果.