在 Golang 中记录和查找 CSV 文件位置

Recording and seeking to CSV file positions in Golang

我需要读取一个 CSV 文件并将具有特定值的行的位置记录到一个数组中,然后返回并以不特定的顺序检索这些行并且性能良好,因此随机访问。

我的程序使用 csv.NewReader(file),但我看不到获取或设置它使用的文件偏移量的方法。我尝试 file.Seek(0,io.SeekCurrent) 到 return 文件位置,但它在调用 reader.Read() 之间不会改变。我还尝试了 fmt.Println("+v +v\n",reader,file) 来查看是否有任何东西存储了 reader 的文件位置,但我没有看到它。如果找到文件位置,我也不知道使用文件位置的最佳方法。

这是我需要做的:

file,_ = os.Open("stuff.csv")
reader = csv.NewReader(file)

//read file and record locations
for {
    line,_ = reader.Read()
    if wantToRememberLocation(line) {
         locations = append(locations, getLocation()) //need this function
    }
}

//then revisit certain lines
for {
    reader.GoToLine(locations[random])  //need this function
    line,_ = reader.Read()
    doStuff(line)
}

是否有一种方法可以使用 csv 库执行此操作,或者我是否必须使用更原始的文件 io 函数编写自己的函数?

这是一个使用 TeeReader 的解决方案。这个例子只是保存了所有的位置并返回并重新读取其中的一些位置。

//set up some vars and readers to record position and length of each line
type Record struct {
    Pos int64
    Len int 
}
records := make([]Record,1)
var buf bytes.Buffer
var pos int64
file,_ := Open("stuff.csv")
tr := io.TeeReader(file, &buf)
cr := csv.NewReader(tr)

//read first row and get things started
data,_ := cr.Read()
dostuff(data)
//length of current row determines position of next
lineBytes,_ := buf.ReadBytes('\n')
length := len(lineBytes)
pos += int64(length)
records[0].Len = length
records = append(records, Record{ Pos: pos })

for i:=1;;i++ {
    //read csv data
    data,err = c.Read()
    if err != nil {break}
    dostuff(data)
    //record length and position
    lineBytes,_ = buf.ReadBytes('\n')
    lenth = len(lineBytes)
    pos += int64(length)
    records[i].Len = length
    records = append(records, Record{ Pos: pos })
}

//prepare individual line reader
line := make([]byte,1000)
lineReader := bytes.NewReader(line)

//read random lines from file
for {
    i := someLineNumber()
    //use original file reader to fill byte slice with line
    file.ReadAt(line[:records[i].Len], records[i].Pos)
    //need new lineParser to start at beginning every time
    lineReader.Seek(0,0)
    lineParser := csv.NewReader(lineReader)
    data,_ = lineParser.Read()
    doStuff(data)
}

os.Open returns 一个实现 io.Seeker 的文件。

所以您可以这样做来将流倒回到开头:

_, err = file.Seek(0, io.SeekStart)

https://golang.org/src/os/file.go