基本信息
- 介绍:cli进度小工具
- 看这个源码的原因:mitchellh大佬写的,代码也不多,学习下
- github:github.com/mitchellh/ioprogress
原理
ioprogress定义了实现了自己的Reader,每次调用Read方法时,就会触发绘制进度。
func (r *Reader) Read(p []byte) (int, error) { ... n, err := r.Reader.Read(p) ... if err == nil { if n > 0 { r.drawProgress() } } if err == io.EOF { r.finishProgress() } return n, err }
比如readme中示例的io.Copy,因为io.Copy(dst Writer, src Reader)是一直拷贝src到dst,我们把自定义的Reader传进去,
每次Read的时候,就会调用Reader.Read,就是我们实现的READ方法,就会有进度条了。
// Imagine this came from some external source, such as a network connection, // and that we have the full size of it, such as from a Content-Length HTTP // header. var r io.Reader // Create the progress reader progressR := &ioprogress.Reader{ Reader: r, Size: rSize, } // Copy all of the reader to some local file f. As it copies, the // progressR will write progress to the terminal on os.Stdout. This is // customizable. io.Copy(f, progressR)
关于绘制函数,定义是type DrawFunc func(int64, int64) error,我们可以学习下如何封装抽象,提供最大的灵活性。
首先是定义了func DrawTerminalf(w io.Writer, f DrawTextFormatFunc) DrawFunc和
type DrawTextFormatFunc func(int64, int64) string。DrawTextFormatFunc主要的职责是传入当前进度和总共,返回要绘制的字符串表示。
DrawTerminalf函数接受一个Writer(比如os.Stdout)和DrawTextFormatFunc,包装返回DrawFunc。
type DrawFunc func(int64, int64) error // DrawTextFormatFunc is a callback used by DrawFuncs that draw text in // order to format the text into some more human friendly format. type DrawTextFormatFunc func(int64, int64) string var defaultDrawFunc DrawFunc func init() { defaultDrawFunc = DrawTerminal(os.Stdout) } // DrawTerminalf returns a DrawFunc that draws a progress bar to an io.Writer // that is formatted with the given formatting function. func DrawTerminalf(w io.Writer, f DrawTextFormatFunc) DrawFunc { ... }
官方提供的DrawTextFormatFunc有3个,一个是最简单的,另外两个是DrawTextFormatBar,DrawTextFormatBytes。
所以最终的使用方式就变成了:
1. 如果不指定,用默认的defaultDrawFunc即DrawTerminal(os.Stdout)。
2. 如果想用简单形式,但是希望指定Writer,可以调用DrawTerminal(w io.Writer)自己传入Writer。
3. 如果希望进度条使用其他格式,自己调用func DrawTerminalf(w io.Writer, f DrawTextFormatFunc) DrawFunc,传入官方提供的
DrawTextFormatBar或者DrawTextFormatBytes。
4. 还是不满足就自己实现接口就好。
不错的学习点
- golang interface的实现,方便我们实现自定义的行为,只要接口一致。
- 作为lib,提供合适封装和抽象的接口,不指定时使用默认行为,有个性化需求就使用自定义的接口实现。