将指针传递给bufio.Scanner()

时间:2017-12-29 17:50:13

标签: go concurrency memory-mapped-files

为免我提供an XY problem,我的目标是在多个goroutine as recommended之间共享内存映射文件。每个goroutine需要逐行遍历文件,所以我希望首先将完整的内容存储在内存中以加快速度。

我尝试的方法是将指针传递给bufio.Scanner,但这不起作用。我认为这可能与需要将搜索位置设置回文件的开头有关,但它甚至不是第一次工作,我在文档中找不到这样的参数。我的尝试是创建这个函数然后通过引用传递结果我打算在goroutine中运行的函数(现在,我使用goroutines 只是为了制作确定这完全有效,但事实并非如此。

这是一个MWE:

// ... package declaration; imports; yada yada

func main() {
    // ... validate path to file stored in filePath variable
    filePath := "/path/to/file.txt"

    // get word list scanner to be shared between goroutines
    scanner := getScannerPtr(&filePath)

    // pass to function (no goroutine for now, I try to solve one problem at a time)
    myfunc(scanner)
}

func getScannerPtr(filePath *string) *bufio.Scanner {
    f, err := os.Open(*filePath)
    if err != nil {
        fmt.Fprint(os.Stderr, "Error opening file\n")
        panic(err)
    }
    defer f.Close()
    scanner := bufio.NewScanner(f)
    scanner.Split(bufio.ScanLines)
    return scanner
}

func myfunc(scanner *bufio.Scanner) {
    for scanner.Scan() {
        line := strings.TrimSpace(scanner.Text())
        // ... do something with line
    }
}

我没有收到任何错误,它只是在我调用Scan()时没有迭代文件,因此它永远不会在该块内部对文件的每一行做任何事情。请记住,我甚至没有使用并发,这只是我最终的目标,我想指出,以防影响我需要采取的方法。

  • 为什么Scan()无效?
  • 如果我打算将来打电话给go myfunc(scanner),这是否可行?

1 个答案:

答案 0 :(得分:4)

您在使用Scanner

之前关闭了该文件
func getScannerPtr(filePath *string) *bufio.Scanner {
    f, err := os.Open(*filePath)
    if err != nil {
        fmt.Fprint(os.Stderr, "Error opening file\n")
        panic(err)
    }
    defer f.Close() // <--- Here
    scanner := bufio.NewScanner(f)
    scanner.Split(bufio.ScanLines)
    return scanner // <-- File gets closed, then Scanner that tries to read it is returned for further use, which won't work
}

由于Scanner未公开Close,因此您需要解决此问题;最快的可能是创建一个包含几个嵌入字段的简单自定义类型:

type FileScanner struct {
    io.Closer
    *bufio.Scanner
}

func getScannerPtr(filePath *string) *FileScanner  {
    f, err := os.Open(*filePath)
    if err != nil {
        fmt.Fprint(os.Stderr, "Error opening file\n")
        panic(err)
    }
    scanner := bufio.NewScanner(f)
    return &FileScanner{f, scanner}
}

func myfunc(scanner *FileScanner) {
    defer scanner.Close()
    for scanner.Scan() {
        line := strings.TrimSpace(scanner.Text())
        // ... do something with line
    }
}