在scanner.Scan()调用后,reader.ReadLine()不会前进

时间:2016-05-13 09:15:08

标签: go

以下代码从此文件中读取其值:

2 3\n
1.0 2.0 3.0\n
-1.0 -2.0 -3.0\n

应该打印: [ {1 2 3}, {-1 -2 -3} ]

但我得到了这个:

[{2 [31 2 3]} {0 []}] strconv.ParseFloat: parsing "3.0-1.0": invalid syntax

似乎reader.ReadLine()停留在同一位置。是否有更简单的方法来扫描线条,然后是每条线内的值?

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type Example struct {
    classLabel int
    attributes []float64
}

func NewExample(classLabel int, attributes []float64) *Example {
    return &Example{classLabel, attributes}
}

func readFile(path string) ([]Example, error) {

    var (
        result       []Example
        err          error
        file         *os.File
        part         []byte
        size         int
        attributeNum int
    )

    if file, err = os.Open(path); err != nil {
        return result, err
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 0))

    if part, _, err = reader.ReadLine(); err != nil {
        return result, err
    }
    buffer.Write(part)
    newLine := buffer.String()
    fmt.Println("newLine=" + newLine)

    r := strings.NewReader(newLine)
    scanner := bufio.NewScanner(r)
    scanner.Split(bufio.ScanWords)

    if scanner.Scan() {
        size, err = strconv.Atoi(scanner.Text())
        if err != nil {
            return result, err
        }
    }
    fmt.Println("size=" + strconv.Itoa(size))

    if scanner.Scan() {
        attributeNum, err = strconv.Atoi(scanner.Text())
        if err != nil {
            return result, err
        }
    }
    fmt.Println("attributeNum=" + strconv.Itoa(attributeNum))

    result = make([]Example, size)

    var classLabel int
    var attributes []float64

    for k := 0; k < size; k++ {
        if part, _, err = reader.ReadLine(); err != nil {
            return result, err
        }
        buffer.Write(part)
        newLine := buffer.String()
        fmt.Println("newLine=" + newLine)

        r := strings.NewReader(newLine)
        scanner := bufio.NewScanner(r)
        scanner.Split(bufio.ScanWords)

        if scanner.Scan() {
            classLabel, err = strconv.Atoi(scanner.Text())
            if err != nil {
                return result, err
            }
        }
        fmt.Println("classLabel=" + strconv.Itoa(classLabel))

        for i := 0; i < attributeNum; i++ {
            var attribute float64
            if scanner.Scan() {
                attribute, err = strconv.ParseFloat(scanner.Text(), 64)
                if err != nil {
                    return result, err
                }
                attributes = append(attributes, attribute)
                fmt.Println("attribute=" + strconv.FormatFloat(attribute, 'f', -1, 64))
            }
        }
        result[k] = *NewExample(classLabel, attributes)
    }

    return result, scanner.Err()
}

func main() {
    example, err := readFile("test.txt")
    fmt.Println(example, err)
}

1 个答案:

答案 0 :(得分:3)

for循环中执行此操作时:

buffer.Write(part)
newLine := buffer.String()
fmt.Println("newLine=" + newLine)

下一行会附加到buffer。 那是, 在循环开始之前,buffer包含2 3, 然后在阅读1.0 2.0 3.0后, 它被附加到缓冲区, 所以内容变成2 31.0 2.0 3.0, 你存储在newLine中。 这就是事情开始横行的地方。

您可能希望在阅读每个新行之前清除buffer

buffer.Reset()
buffer.Write(part)
newLine := buffer.String()
fmt.Println("newLine=" + newLine)

但是接下来你还会遇到更多问题:

    if scanner.Scan() {
        classLabel, err = strconv.Atoi(scanner.Text())
        if err != nil {
            return result, err
        }
    }

由于该行包含1.0 2.0 3.0strconf.Atoi将失败。 我不明白这个片段的目的, 也许你可以删除它(或注释掉)。

在上面修复后,你还会遇到另外一个问题:

          attributes = append(attributes, attribute)

由于attributes永远不会重置,因此它会不断增长。 也就是说,在第一行之后,它将包含1 2 3, 在第二行之后它将包含1 2 3 -1 -2 -3。 您可以通过移动attributes的声明而不使用外部循环来纠正这一点,如下所示:

    var attributes []float64
    for i := 0; i < attributeNum; i++ {
        var attribute float64
        if scanner.Scan() {
            attribute, err = strconv.ParseFloat(scanner.Text(), 64)
            if err != nil {
                return result, err
            }
            attributes = append(attributes, attribute)
            fmt.Println("attribute=" + strconv.FormatFloat(attribute, 'f', -1, 64))
        }
    }