以下代码从此文件中读取其值:
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)
}
答案 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.0
,strconf.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))
}
}