《go语言程序设计》学习(八)

一,过滤

package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "path/filepath"
    "runtime"
    "strings"
)

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU()) // Use all the machine's cores
    log.SetFlags(0)
    algorithm,
        minSize, maxSize, suffixes, files := handleCommandLine()

    if algorithm == 1 {
        sink(filterSize(minSize, maxSize, filterSuffixes(suffixes, source(files))))
    } else {
        channel1 := source(files)
        channel2 := filterSuffixes(suffixes, channel1)
        channel3 := filterSize(minSize, maxSize, channel2)
        sink(channel3)
    }
}

func handleCommandLine() (algorithm int, minSize, maxSize int64,
    suffixes, files []string) {
    flag.IntVar(&algorithm, "algorithm", 1, "1 or 2")
    flag.Int64Var(&minSize, "min", -1,
        "minimum file size (-1 means no minimum)")
    flag.Int64Var(&maxSize, "max", -1,
        "maximum file size (-1 means no maximum)")
    var suffixesOpt *string = flag.String("suffixes", "",
        "comma-separated list of file suffixes")
    flag.Parse()
    if algorithm != 1 && algorithm != 2 {
        algorithm = 1
    }
    if minSize > maxSize && maxSize != -1 {
        log.Fatalln("minimum size must be < maximum size")
    }
    suffixes = []string{}
    if *suffixesOpt != "" {
        suffixes = strings.Split(*suffixesOpt, ",")
    }
    files = flag.Args()
    return algorithm, minSize, maxSize, suffixes, files
}

func source(files []string) <-chan string {
    out := make(chan string, 1000)
    go func() {
        for _, filename := range files {
            out <- filename
        }
        close(out)
    }()
    return out
}

// make the buffer the same size as for files to maximize throughput
func filterSuffixes(suffixes []string, in <-chan string) <-chan string {
    out := make(chan string, cap(in))
    go func() {
        for filename := range in {
            if len(suffixes) == 0 {
                out <- filename
                continue
            }
            ext := strings.ToLower(filepath.Ext(filename))
            for _, suffix := range suffixes {
                if ext == suffix {
                    out <- filename
                    break
                }
            }
        }
        close(out)
    }()
    return out
}

// make the buffer the same size as for files to maximize throughput
func filterSize(minimum, maximum int64, in <-chan string) <-chan string {
    out := make(chan string, cap(in))
    go func() {
        for filename := range in {
            if minimum == -1 && maximum == -1 {
                out <- filename // don't do a stat call it not needed
                continue
            }
            finfo, err := os.Stat(filename)
            if err != nil {
                continue // ignore files we can't process
            }
            size := finfo.Size()
            if (minimum == -1 || minimum > -1 && minimum <= size) &&
                (maximum == -1 || maximum > -1 && maximum >= size) {
                out <- filename
            }
        }
        close(out)
    }()
    return out
}

func sink(in <-chan string) {
    for filename := range in {
        fmt.Println(filename)
    }
}

这段过滤是一个很简单大功能,设定一些参数就可以了。实现方式是类unix管道的方式,也就是串行。

首先使用了flag包把命令行参数解析出来,包括suffix,大小范围和文件名范围,然后依次建立了3个channel。

第一个channel到写端是把文件名列表解析成一个一个的文件名。

第二个channel的写端,是把第一个文件名按suffix做一次过滤后的结果。

第三个channel的写端,是把第二个的文件名按大小范围过滤后的结果。

最后一个sink读取第三个channel后,把结果打印出来。

嗯。。参数不同,有个分支只过滤了一次。。

关于flag包。。搜了下,解析参数时候是这样的:首先参数定义有两种,一种是带有-符号的一种是没有-符号的。flag的方法parse就是解析出来带有-符号的,flag的args方法就是获取其他参数的。好像就没啥别的太特别的了~

关于channel和goroutin,好像这儿没啥特别要说明的~

原文地址:https://www.cnblogs.com/mruoli/p/4709362.html