如何在匿名函数中逐行扫描文件并将其传递到通道

How to scan a file line by line in an anonymous function and pass it down a channel

我想编写一个函数,从文件中读取行,然后将其发送到通道以进行进一步处理。我是 Go 的新手,这里是 reader 函数,我想出了以下大部分教科书示例:

func reader(file string) <-chan string {
    out := make(chan string)

    f, err := os.Open(file)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()

    s := bufio.NewScanner(f)
    go func() {
        for s.Scan() {
            out <- s.Text()
        }
        close(out)
    }()

    return out
}

main() 函数中,我将一个文件指针传递给 reader 函数,并尝试按如下方式排出输出通道:

func main() {
    out := reader(*f)
    for range out {
        fmt.Println(<-out)
    }
}

我没有收到编译或运行时错误,但是输出为空。如果我不将 for 循环放入 goroutine 中,我可以使用 reader() 函数打印文件 w/o 任何问题。

我还尝试将 reader() 函数中的扫描器、通道或两者都传递给匿名函数。但这并没有解决问题。谁能解释为什么此代码不起作用以及如何补救?

您正在关闭文件,然后再阅读它。

您只是每隔一行打印一次。

将延迟移动到实际发生读取的闭包中。

func reader(file string) <-chan string {
    out := make(chan string)

    f, err := os.Open(file)
    if err != nil {
        log.Fatal(err)
    }

    s := bufio.NewScanner(f)
    go func() {
        defer f.Close()
        defer close(out)
        for s.Scan() {
            out <- s.Text()
        }
        if err := s.Err(); err != nil {
            fmt.Println("error reading file:", err)
        }
    }()

    return out
}

然后打印 range 子句中的值,而不是 for 循环中收到的第二个值:

func main() {
    out := reader(os.Args[1])
    for line := range out {
        fmt.Println(line)
    }
}