buffo.Scanner逐行读取文件的奇怪行为

时间:2014-07-23 20:06:51

标签: go

我使用bufio.Scanner将文件逐行读入变量wordlist([] [] byte)

这是代码(使用go 1.1 / 1.3进行测试)。

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

func main() {
    fle, err := os.Open("words.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer fle.Close()

    scanner := bufio.NewScanner(fle)

    n := 1000
    dCnt := 5
    var wordlist [][]byte

    for scanner.Scan() {
        if len(wordlist) == n {
            break
        }
        word := scanner.Bytes()
        for ii := 0; ii < len(wordlist); ii++ {
            if string(word) == string(wordlist[ii]) {
                log.Println(ii, string(word), string(wordlist[ii]))
                log.Println(len(wordlist), "double")

                dCnt--
                if dCnt == 0 {
                    for i, v := range wordlist {
                        fmt.Println(i, string(v))
                    }
                    log.Fatal("double")
                }
            }
        }
        wordlist = append(wordlist, word)
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}

words.txt是一个包含5040行序列排列的文件&#34; abcdefg&#34;:

line 1 .. 
abcdefg
abcdegf
abcdfeg
abcdfge
..
line 510 ..
afcdbge
afcdebg
afcdegb
afcdgbe
afcdgeb
.. line 5040

由这个小python脚本生成:

from itertools import permutations as perm
c = "abcdefg"
p = perm(c, len(c))
with file('words.txt','wb') as outFle:
    for i in xrange(5040):
        n = ''.join(p.next())
        print >> outFle, n

问题是,在运行上述go程序后,wordlist包含以下内容:

索引字符串(wordlist [])

0 afcdebg      <-- this is line 513 of words.txt
1 afcdegb
2 afcdgbe
3 afcdgeb
...
510 bdefcag
511 bdefcga
512 afcdebg    <-- this is the begin of a repition of line 513 .. 1024 in words.ttx
513 afcdegb
514 afcdgbe 

相反,wordlist应该包含前1000行words.txt

任何想法?

答案由Daniel Darabos(见下文)提供。

更改

word:= scanner.Bytes()

word:= scanner.Text()&#39;做了这个工作。

(感谢您的帮助!)

1 个答案:

答案 0 :(得分:8)

Scanner.Bytes的文档说:

  

基础数组可能指向将被后续调用Scan覆盖的数据。

因此,如果保存返回的切片,您可以期望看到其内容发生变化。这会对您的应用程序造成严重破坏。最好不要保存返回的切片!

一个很好的解决方案是从字节构建一个字符串:

word := string(scanner.Bytes())

然后你可以在任何地方使用字符串,代码变得更加愉快。

发生了什么事?

为什么Scanner.Bytes恨我?答案也在文档中:

  

没有分配。

这使得扫描仪非常高效。从你看到的,我猜它在构造函数中为512行分配缓冲区,然后在它们上面旋转。

在不需要保留对行的引用的应用程序中,这不是问题。 (例如,类似grep的程序只查看每一行。)通常,您解析该行并存储对该行的引用。但是如果要存储原始字节数据,则负责将其从Scanner复制出来。

这可能很麻烦,但是虽然你可以在不方便的行为之上实现方便的行为,但是在低效行为之上实现有效行为是不可能的。


另一个用于生成输入的简单脚本:

import itertools
for p in itertools.permutations('abcdefg'):
  print ''.join(p)