golang:读取文件生成器

时间:2016-05-26 10:23:36

标签: python go generator

我正在学习 go 语言并尝试使用golang重写我的一些Python代码。 我写了一个生成器函数,它逐行读取文本文件并发送(使用 yield 关键字)只有“有效”行(忽略空白行,重新构造未完成的行)。

示例文件(myfile.txt):

#123= FOOBAR(1.,'text');

#126= BARBAZ('poeazpfodsp',
234,56);

parse.py:

#!/usr/bin/python
def validlines(filename):
    with open(filename) as fdin:
        buff = ''
        for line in fdin.readlines():
            line = line.strip()
            if line == '':
                continue
            buff += line
            if line[-1] != ';':
                continue
            yield buff
            buff = ''
        fdin.close()

for line in validlines('myfile.txt'):
    print(line) 

显示:

#123= FOOBAR(1.,'text');
#126= BARBAZ('poeazpfodsp',234,56);    

现在,我尝试使用golang中的闭包来完成相同的操作:

parse.go:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func validLines(filename string) (func() (string, bool)) {

    file, _ := os.Open(filename)
    scanner := bufio.NewScanner(file)

    return func() (string, bool) {
        buff := ""
        for scanner.Scan() {
            line := scanner.Text()
            line = strings.TrimSpace(line)

            if line == "" {
                continue
            }
            buff += line
            if line[len(line)-1] != ';' {
                continue
            }
            return buff, true
        }

        file.Close()
        return "", false
    }
}

func main() {
    vline := validLines("myfile.txt")
    for line, ok := vline(); ok; {
        fmt.Println(line)
    }
}

显示:

#123= FOOBAR(1.,'text');
#123= FOOBAR(1.,'text');
#123= FOOBAR(1.,'text');
#123= FOOBAR(1.,'text');
#123= FOOBAR(1.,'text');
#123= FOOBAR(1.,'text');
#123= FOOBAR(1.,'text');
...

在golang中正确的做法是什么?

4 个答案:

答案 0 :(得分:6)

在Go中你可以使用频道而不是收益,这非常方便。

package main

curl -v orion:1026/v2/entities/Bcn-Welt/attrs/humidity/value --header "Accept: text/plain" --header "Accept: application/json"
* Hostname was NOT found in DNS cache
*   Trying 172.17.0.13...
* Connected to orion (172.17.0.13) port 1026 (#0)
> GET /v2/entities/Bcn-Welt/attrs/humidity/value HTTP/1.1
> User-Agent: curl/7.35.0
> Host: orion:1026
> Accept: text/plain
> Accept: application/json
> 
< HTTP/1.1 406 Not Acceptable
< Connection: Keep-Alive
< Content-Length: 73
< Content-Type: application/json
< Fiware-Correlator: 375fb1a8-232c-11e6-a21e-0242ac11000d
< Date: Thu, 26 May 2016 10:25:49 GMT
< 
* Connection #0 to host orion left intact
{"error":"NotAcceptable","description":"accepted MIME types: text/plain"}

答案 1 :(得分:2)

只需添加pav5000's answer,您就应该对频道进行缓冲:
c:= make(chan string,1)
否则,它会将整个文件读入一个频道,没有必要使用它。

答案 2 :(得分:1)

这是你的主要的for循环,这是问题所在。使用这种语法,它的作用如下:

  1. 首次调用line
  2. 初始化okvline()
  3. 如果ok为真,则运行一次循环
  4. 在块的末尾更新一些内容,然后转到2.
  5. 因此,您的问题是您永远不会更新lineok。这是正确的版本:

    for line, ok := vline(); ok; line, ok = vline() { ... }
    

答案 3 :(得分:1)

小变化:

func main() {
    vline := validLines("myfile.txt")
    line, ok := vline()
    for ok  {
        fmt.Println(line)
        line, ok = vline()
    }
}