将指针传递给bufio.Scanner() [英] Passing a pointer to bufio.Scanner()

查看:180
本文介绍了将指针传递给bufio.Scanner()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了避免我提供 XY问题,我的目标是在多个goroutine 建议使用。每个goroutine都需要逐行遍历文件,因此我希望先将完整的内容存储在内存中以加快速度。

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



这是一个MWE:

  // ...包装声明;进口; yada yada 

func main(){
// ...验证存储在filePath变量中的文件路径
filePath:=/path/to/file.txt

//获取单词列表扫描器以便在goroutines之间共享
scanner:= getScannerPtr(&filePath)

//传递给函数(现在没有goroutine,我尝试一次解决一个问题)
myfunc(scanner)
}

func getScannerPtr(filePath * string)* bufio.Scanner {
f,err: = os.Open(* filePath)
if err!= nil {
fmt.Fprint(os.Stderr,Error opening file\\\

panic(err)

推迟f.Close()
扫描器:= bufio.NewScanner(f)
scanner.Split(bufio.ScanLines)
返回扫描器
}

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

执行某些操作receivi如果我调用 Scan(),它不会在该块内部对文件的每一行执行任何操作。请记住,我甚至没有使用并发性,这只是我最终想要指出的一个目标,以防影响我需要采用的方法。


  • 为什么 Scan()无法使用?

  • 如果我打算今后调用 go myfunc(scanner),这是一种可行的方法吗?


解决方案

在使用 Scanner 之前,您正在关闭文件:


$ b $

  func getScannerPtr(filePath * string)* bufio.Scanner {
f,err:= os.Open(* filePath)
如果错误!= nil {
fmt.Fprint(os.Stderr,Error opening file\\\

panic(err)
}
推迟f.Close( )//< ---这里
scanner:= bufio.NewScanner(f)
scanner.Split(bufio.ScanLines)
返回扫描器//< - 文件被关闭,那么试图读取它的扫描仪将被返回供进一步使用,这将不起作用
}



<因为 Scanner 不公开关闭,您需要解决此问题;最快的可能是用一些嵌入字段来创建一个简单的自定义类型:

$ p $ 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 \\\

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())
// ...用行
}
}


Lest I provide an XY problem, my goal is to share a memory-mapped file between multiple goroutines as recommended. Each goroutine needs to iterate over the file line by line so I had hoped to store the complete contents in memory first to speed things up.

The method I tried is passing a pointer to a bufio.Scanner, but that is not working. I thought it might be related to needing to set the seek position back to the beginning of the file but it is not even working the very first time and I can find no such parameter in the documentation. My attempt was to create this function then pass the result by reference to the function I intend to run in a goroutine (for right now, I am not using goroutines just to make sure this works outright, which it does not).

Here is a 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
    }
}

I'm not receiving any errors, it just is not iterating over the file when I call Scan() so it never makes it inside that block to do anything with each line of the file. Keep in mind I am not even using concurrency yet, that is just my eventual goal which I want to point out in case that impacts the method I need to take.

  • Why is Scan() not working?
  • Is this is a viable approach if I intend to call go myfunc(scanner) in the future?

解决方案

You're closing the file before you ever use the 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
}

Because Scanner does not expose Close, you'll need to work around this; the quickest is probably to make a simple custom type with a couple of embedded fields:

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
    }
}

这篇关于将指针传递给bufio.Scanner()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆