在Go中读取CSV文件
我在学围棋。以下是读取CSV文件的代码段:在Go中读取CSV文件,go,Go,我在学围棋。以下是读取CSV文件的代码段: func parseLocation(file string) (map[string]Point, error) { f, err := os.Open(file) defer f.Close() if err != nil { return nil, err } lines, err := csv.NewReader(f).ReadAll() if err != nil {
func parseLocation(file string) (map[string]Point, error) {
f, err := os.Open(file)
defer f.Close()
if err != nil {
return nil, err
}
lines, err := csv.NewReader(f).ReadAll()
if err != nil {
return nil, err
}
locations := make(map[string]Point)
for _, line := range lines {
name := line[0]
lat, laterr := strconv.ParseFloat(line[1], 64)
if laterr != nil {
return nil, laterr
}
lon, lonerr := strconv.ParseFloat(line[2], 64)
if lonerr != nil {
return nil, lonerr
}
locations[name] = Point{lat, lon}
}
return locations, nil
}
有没有办法提高这段代码的可读性?if和nil noise。Go是一种非常冗长的语言,但是您可以使用如下内容:
// predeclare err
func parseLocation(file string) (locations map[string]*Point, err error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close() // this needs to be after the err check
lines, err := csv.NewReader(f).ReadAll()
if err != nil {
return nil, err
}
//already defined in declaration, no need for :=
locations = make(map[string]*Point, len(lines))
var lat, lon float64 //predeclare lat, lon
for _, line := range lines {
// shorter, cleaner and since we already have lat and err declared, we can do this.
if lat, err = strconv.ParseFloat(line[1], 64); err != nil {
return nil, err
}
if lon, err = strconv.ParseFloat(line[2], 64); err != nil {
return nil, err
}
locations[line[0]] = &Point{lat, lon}
}
return locations, nil
}
//编辑
在中发布了一个更有效、更合适的版本,为了完整起见,我在这里添加它:
func parseLocation(file string) (map[string]*Point, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
csvr := csv.NewReader(f)
locations := map[string]*Point{}
for {
row, err := csvr.Read()
if err != nil {
if err == io.EOF {
err = nil
}
return locations, err
}
p := &Point{}
if p.lat, err = strconv.ParseFloat(row[1], 64); err != nil {
return nil, err
}
if p.lon, err = strconv.ParseFloat(row[2], 64); err != nil {
return nil, err
}
locations[row[0]] = p
}
}
我基本上是从这里复制了我的答案:。对我来说,这是一个比我在stackoverflow上找到的更好的答案
import (
"bufio"
"encoding/csv"
"os"
"fmt"
"io"
)
func ReadCsvFile(filePath string) {
// Load a csv file.
f, _ := os.Open(filePath)
// Create a new reader.
r := csv.NewReader(f)
for {
record, err := r.Read()
// Stop at EOF.
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
// Display record.
// ... Display record length.
// ... Display all individual elements of the slice.
fmt.Println(record)
fmt.Println(len(record))
for value := range record {
fmt.Printf(" %v\n", record[value])
}
}
}
您还可以读取目录的内容以加载所有CSV文件。然后使用
goroutines
csv
文件:
101,300.00,11000901,1155686400
102,250.99,11000902,1432339200
const sourcePath string = "./source"
func main() {
dir, _ := os.Open(sourcePath)
files, _ := dir.Readdir(-1)
for _, file := range files {
fmt.Println("SINGLE FILE: ")
fmt.Println(file.Name())
filePath := sourcePath + "/" + file.Name()
f, _ := os.Open(filePath)
defer f.Close()
// os.Remove(filePath)
//func
go func(file io.Reader) {
records, _ := csv.NewReader(file).ReadAll()
for _, row := range records {
fmt.Println(row)
}
}(f)
time.Sleep(10 * time.Millisecond)// give some time to GO routines for execute
}
}
main.go
文件:
101,300.00,11000901,1155686400
102,250.99,11000902,1432339200
const sourcePath string = "./source"
func main() {
dir, _ := os.Open(sourcePath)
files, _ := dir.Readdir(-1)
for _, file := range files {
fmt.Println("SINGLE FILE: ")
fmt.Println(file.Name())
filePath := sourcePath + "/" + file.Name()
f, _ := os.Open(filePath)
defer f.Close()
// os.Remove(filePath)
//func
go func(file io.Reader) {
records, _ := csv.NewReader(file).ReadAll()
for _, row := range records {
fmt.Println(row)
}
}(f)
time.Sleep(10 * time.Millisecond)// give some time to GO routines for execute
}
}
输出将是:
$go运行main.go
-----------------------------------------------------------
-----------------------------------
下面是带有发票结构的示例
Go now为此提供了一个csv包。它是编码/csv
。您可以在此处找到文档:
文档中有几个很好的例子。下面是我创建的一个助手方法,用于读取csv文件并返回其记录
主程序包
进口(
“编码/csv”
“fmt”
“日志”
“操作系统”
)
func readCsvFile(文件路径字符串)[]字符串{
f、 错误:=os.Open(文件路径)
如果错误!=零{
log.Fatal(“无法读取输入文件”+文件路径,错误)
}
延迟f.关闭()
csvReader:=csv.NewReader(f)
记录,错误:=csvReader.ReadAll()
如果错误!=零{
log.Fatal(“无法将“+文件路径”的文件解析为CSV,错误)
}
退货记录
}
func main(){
记录:=readCsvFile(../tasks.csv)
fmt.Println(记录)
}
我也不喜欢默认阅读器的冗长,所以我创建了一个新类型
与bufio扫描仪类似:
package main
import "encoding/csv"
import "io"
type Scanner struct {
Reader *csv.Reader
Head map[string]int
Row []string
}
func NewScanner(o io.Reader) Scanner {
csv_o := csv.NewReader(o)
a, e := csv_o.Read()
if e != nil {
return Scanner{}
}
m := map[string]int{}
for n, s := range a {
m[s] = n
}
return Scanner{Reader: csv_o, Head: m}
}
func (o *Scanner) Scan() bool {
a, e := o.Reader.Read()
o.Row = a
return e == nil
}
func (o Scanner) Text(s string) string {
return o.Row[o.Head[s]]
}
例如:
package main
import "strings"
func main() {
s := `Month,Day
January,Sunday
February,Monday`
o := NewScanner(strings.NewReader(s))
for o.Scan() {
println(o.Text("Month"), o.Text("Day"))
}
}
if err!=nil
:如果此时出现错误,这是因为文件无法打开,因此,您不能对其使用Close
。@julienc在错误检查后不需要使用DEREF语句。您当然可以关闭未打开的文件:我建议不要命名这些返回变量。你甚至不用它们的名字,这只会引起额外的混乱。在解析之前,一次将整个内容读入内存是不必要的。我们应该避免这样做。lat/long predeclaration的范围太大,但实际上没有必要。我会这样做:你应该把这个作为一个答案,你得到了我的支持。我考虑过,但它几乎是你的答案,只是有一些小的改变。我最担心的是内存消耗,但你是从原始版本中取出来的。@其中一个为什么你会说go是“一种非常冗长的语言”@user3666882因为它是,没有像大多数其他语言一样的“快捷方式”,我的意思是甚至没有trinity运算符。对于u,value:=range reader{fmt.Printf(“%v\n”,value)}
也可以