我有一个文本文件,其中包含多行,以空行分隔。 在Go中逐行读取该行的最佳方法是什么?

我想我可能必须将扫描仪与我自己的分割功能一起使用,但是只是想知道是否有一种更好/更容易的方式而遗失了。

我尝试使用基于bufio.ScanLines的自己的Splitfunc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func MyScanLines(data []byte, atEOF bool) (advance int, token []byte,    err error) {
    if atEOF && len(data) == 0 {
            return 0, nil, nil
    }
    if i := bytes.IndexAny(data,"

"); i >= 0 {
            return i + 1, dropCR(data[0:i]), nil
    }
    if atEOF {
            return len(data), dropCR(data), nil
    }
    return 0, nil, nil
}

但是在IndexAny调用中出现错误:
"语法错误:意外的分号或换行符,期待)"-修复了该问题

更新:按建议修复了上面的语法错误,但是我只得到返回的第一行。 我正在读取文件,如下所示:

1
2
3
scanner.Split(MyScanLines)
scanner.Scan()
fmt.Println(scanner.Text())

有什么建议么?

我尝试读取的测试文件示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Name ="John"
Surname ="Smith"
Val1 = 700
Val2 = 800

Name ="Pete"
Surname ="Jones"
Val1 = 555
Val2 = 666
Val3 = 444

 .
 .
 .
  • 请提供您尝试读取的文件样本。
  • @PrashantThakkar现在在原始帖子中提供了示例。 一些值对可能在一个记录中,而不在其他记录中,顺序也不固定。
  • 谢谢,对于您所得到的错误,它清楚地表明缺少")"。 已更正:如果i:= bytes.IndexAny(data," n n"); i> = 0 {
  • @PrashantThakkar啊,不! 我一直在盯着那个代码,没有去接它。 啊。 感谢那。 是我推荐的方式吗?

这是使用bufio.Reader进行此操作的另一种方法。逻辑几乎与Elwiner的答案相似。

下面的myReadLine函数使用bufio.Reader读取文件中的下一个多行条目。

1
2
3
4
5
6
7
8
9
10
func myReadLine(file *os.File, reader *bufio.Reader) (lines []string, err error){
  for {
    line, _, err := reader.ReadLine()
    if err != nil || len(line) == 0 {
      break
    }
    lines = append(lines, string(line))
  }
  return lines, err
}

下面的代码示例说明了上述功能的示例用法:

1
2
3
4
5
6
7
8
reader := bufio.NewReader(file)
for {
    lines, err := myReadLine(file, reader)
    if err != nil || len(lines) == 0 {
        break
    }
    fmt.Println(lines)
}

您的方式正常,但我建议您使用bufio.Scanner,默认情况下是逐行扫描。
然后,您就可以开始逐行读取文件并填充结构。遇到空白行时,将您的结构切成片并从新的结构开始。

这是一个示例,摘自我的一个开源项目进行了演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
buffer := [][]string{}
block := []string{}
scanner := bufio.NewScanner(strings.NewReader(data))
for scanner.Scan() {
    l := scanner.Text()

    if len(strings.TrimSpace(l)) != 0 {
        block = append(block, l)
        continue
    }

    // At this point, the script has reached an empty line,
    // which means the block is ready to be processed.
    // If the block is not empty, append it to the buffer and empty it.
    if len(block) != 0 {
        buffer = append(buffer, block)
        block = []string{}
    }
}

if len(block) != 0 {
    buffer = append(buffer, block)
}
  • 您的代码无效。 在Go游乐场中查看它:play.golang.org/p/v5aOCK7zRG
  • 感谢您提到它,我有效地颠倒了条件,同时从代码中删除了无关的上下文。 我对其进行了修复,并在最后添加了一张支票以说明文件的末尾。

bufio.Scan()在EOF上返回false。
我们将返回第二个" ok"参数,以便我们的呼叫者可以告诉我们是否
在我们输入的末尾。

最好将我们的记录累积在字符串中,并在末尾进行连接。
将每行依次追加到结果字符串的明显方法是可行的,但行数为O(n ^ 2)。

放在一起:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func ReadBlock(scanner *bufio.Scanner) (string, bool) {
    var o []string
    if scanner.Scan() == false {
        return"", false
    }

    for len(scanner.Text()) > 0 {
        o = append(o, scanner.Text())
        if scanner.Scan() == false {
            break
        }
    }
    return strings.Join(o,""), true
}

https://play.golang.org/p/C_fB8iaYJo

ps。查看您的输入,我怀疑您想将结果作为映射而不是串联字符串返回。


坏了。首先了解扫描并确保其正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

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

func main() {
    scanner := bufio.NewScanner(strings.NewReader(data))
    for scanner.Scan() {
        l := scanner.Text()
        fmt.Println(l)

    }

}

var data = `
Name ="John"
Surname ="Smith"
Val1 = 700
Val2 = 800

Name ="Pete"
Surname ="Jones"
Val1 = 555
Val2 = 666
Val3 = 444
`

这是Go操场上的代码。

接下来,将您需要的数据收集到一个切片中。可能有一种方法可以检查文件结尾EOF,但我找不到它。这是我想出的,并且有效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package main

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

func main() {
    buffer := [][]string{}
    block := []string{}
    scanner := bufio.NewScanner(strings.NewReader(data))
    for scanner.Scan() {
        l := scanner.Text()

        if len(l) != 0 {
            block = append(block, l)
            continue
        }

        if len(l) == 0 && len(block) != 0 {
            buffer = append(buffer, block)
            block = []string{}
            continue
        }

        if len(l) == 0 {
            block = []string{}
            continue
        }

    }

    if len(block) != 0 {
        buffer = append(buffer, block)
        block = []string{}
    }

    fmt.Println("PRINTING BUFFER - END OF PROGRAM - ALL DATA PROCESSED:", buffer)

}

var data = `
Name ="John"
Surname ="Smith"
Val1 = 700
Val2 = 800

Name ="Pete"
Surname ="Jones"
Val1 = 555
Val2 = 666
Val3 = 444
`

这是操场上的代码。

  • 非常感谢!
  • 您基本上接受了我的答案并重新发布了它……您甚至都没有更改变量名称来自己模拟解决问题。 可怜…
  • 目的是解决方案,而不是IP权利或天才创意。 您的代码无效。 我提供了另一个迭代。 我指出了我可以改进我的代码的地方。 有人改进了它,提供了另一个迭代。 团队合作专注于解决方案。 对我而言,这就是stackoverflow的意义:编码人员聚在一起互相帮助。 我没有试图窃取您的代码。 放松一下,玩的很好。 不需要名称调用。