用go写的一个dd程序

最近学了下go语言, 写了几个程序下来觉得确实很方便。

主要是有几点,

  • code syle定死了,省的以后浪费时间在code sytle上面的争论
  • 大括号必须跟在函数后边,只有if和for,简单啊。
  • 最方便的地方就是错误处理,可以返回一个返回值和一个专门处理错误码。
  • 还有就是打的字很少。
  • 用来处理参数的flag很好用,参数处理简单很多。

在主页http://golang.org 上面有许多文档, 另外还有几个中文的文档看着比较舒服:

http://code.google.com/p/golang-china/

http://code.google.com/p/ac-me/

 

package main

import (
	"os"
	"syscall"
	"flag"
	"fmt"
)

var ofile = flag.String("of", "","out file")
var ifile = flag.String("if", "", "in file")
var seek = flag.Int64("seek", 0, "seek bytes")
var skip = flag.Int64("skip", 0, "skip bytes")

func main() {

	flag.Parse()
	
	of := os.Stdout
	inf := os.Stdin
	err := os.EINVAL

	fmt.Printf("of :%s if:%s n", *ofile, *ifile);
	
	if *ofile != "" {
		of, err = os.Create(*ofile)
		if of == nil {
			fmt.Printf("can open of:%s:%sn",
				ofile, err.String())
			os.Exit(1)
		}
	}
	if *ifile != "" {
		inf, err = os.Open(*ifile)
		if inf == nil {
			fmt.Printf("can't oepn if:%s:%sn",
				ifile, err.String())
			os.Exit(1)
		}
	}

	if *seek != 0 {
		sr,err := of.Seek(*seek, os.SEEK_CUR)
		if sr < 0 {
			fmt.Printf("seek error:%s:%sn",
				of.Name(), err.String())
			os.Exit(1)
		}
	}
	if *skip != 0 {
		sr, err := inf.Seek(*skip, os.SEEK_CUR)
		if sr < 0 {
			fmt.Printf("skip error:%s:%sn",
				inf.Name(), err.String())
			os.Exit(1)
		}
	}

	fmt.Printf("dd :%s to %sn",
		inf.Name(), of.Name())
	
	const NBUF = 4096
	var buffer [NBUF]byte

	for {
		switch nr, er := inf.Read(buffer[0:]); true {
		case nr < 0:
			fmt.Fprintf(os.Stderr, "dd: error when reading from %s:%sn", inf.Name(), er.String())
			os.Exit(1)
		case nr == 0:
			inf.Close()
			of.Close()
			return
		case nr > 0:
			if nw, ew := of.Write(buffer[0:nr]); nw != nr{
				fmt.Fprintf(os.Stderr,"dd: error writing to %s:%sn", of.Name(), ew.String())
			}
		}
	}
	syscall.Sync()
}

 

编译:

$ 8g dd.go && 8l -o dd dd.8

运行:

./dd -if qi.tar.gz -of tmp

用一个400M的包做测试:

time ./dd -if qi.tar.gz -of tmp

real    0m16.636s
user    0m0.152s
sys    0m1.764s

比起来要比dd要快一点:

time dd if=qi.tar.gz of=tmp
记录了843029+1 的读入
记录了843029+1 的写出
431631274字节(432 MB)已复制,21.1584 秒,20.4 MB/秒

real    0m21.229s
user    0m0.516s
sys    0m4.624s

不过估计是因为我们的dd里面用的是4K的buffer吧。

time dd if=qi.tar.gz of=tmp bs=4096
记录了105378+1 的读入
记录了105378+1 的写出
431631274字节(432 MB)已复制,13.7601 秒,31.4 MB/秒

real    0m13.925s
user    0m0.040s
sys    0m1.424s

果然, 换成4096的buffer size要比go写的快一点。

总之,用go写程序比较爽。