Запись и поиск позиций в CSV-файле на Голанге - PullRequest
0 голосов
/ 12 апреля 2019

Мне нужно прочитать файл CSV и записать расположение строк с определенными значениями в массив, а затем вернуться назад и получить эти строки в произвольном порядке и с хорошей производительностью, поэтому произвольный доступ.

Моя программа использует csv.NewReader (файл), но я не вижу способа получить или установить смещение файла, которое она использует. Я попытался file.Seek (0, io.SeekCurrent), чтобы вернуть позицию файла, но он не меняется между вызовами reader.Read (). Я также попытался fmt.Println ("+ v + v \ n", читатель, файл), чтобы увидеть, хранит ли что-нибудь положение файла читателя, но я этого не вижу. Я также не знаю, как лучше всего использовать положение файла, если я его найду.

Вот что мне нужно сделать:

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, или мне придется написать свою собственную, используя более примитивные функции ввода-вывода файлов?

Ответы [ 2 ]

0 голосов
/ 12 мая 2019

os.Open возвращает файл, который реализует io.Seeker.

Таким образом, вы можете сделать это, чтобы перемотать поток в начало:

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

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

0 голосов
/ 13 апреля 2019

Вот решение с использованием 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)
}

...