#csv #go
#csv #Вперед
Вопрос:
Я обрабатываю файлы csv, и когда я прерываю процесс, я хочу сохранить необработанные данные в другой файл.
Это то, что я сделал
csvFile, err := os.Open(csvPath)
r := csv.NewReader(csvFile)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
go func() {
<-sigc
savePending(r)
}()
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Println(record, err)
continue
}
doSomethingWithRecord(record)
}
Функция сохранения
func savePending(r *csv.Reader) {
pendingFileName := fmt.Sprintf("%s_pending.csv", fileBaseName)
csvPendingPath := path.Join(dirname, pendingFileName)
pendingFile, err := os.Create(csvPendingPath)
if err != nil {
log.Fatalln("Couldn't open the csv file", csvPendingPath, err)
}
defer pendingFile.Close()
pendR := csv.NewWriter(pendingFile)
records, err := r.ReadAll()
if err == io.EOF {
log.Println("no pending records")
}
err = pendR.WriteAll(records)
if err != nil {
log.Println("error writing pending file")
}
}
Но когда я запускаю код, а затем прерываю скрипт, нажимая CTRL C, у меня всегда возникает паника
panic: runtime error: slice bounds out of range [:7887] with capacity 4096
goroutine 82 [running]:
bufio.(*Reader).ReadSlice(0xc0000c2ea0, 0x105930a, 0x88, 0x90, 0xc00090cab0, 0x0, 0x0)
/usr/local/Cellar/go/1.13.3/libexec/src/bufio/bufio.go:334 0x232
encoding/csv.(*Reader).readLine(0xc00015c1b0, 0x9, 0x9, 0xc00090cab0, 0xc00090f680, 0x20e)
/usr/local/Cellar/go/1.13.3/libexec/src/encoding/csv/reader.go:218 0x49
encoding/csv.(*Reader).readRecord(0xc00015c1b0, 0x0, 0x0, 0x0, 0xc00090cab0, 0x9, 0x9, 0x0, 0x0)
/usr/local/Cellar/go/1.13.3/libexec/src/encoding/csv/reader.go:266 0x115
encoding/csv.(*Reader).ReadAll(0xc00015c1b0, 0xc0005af2c0, 0x1000, 0xc0006fc000, 0xc0001da608, 0x0)
/usr/local/Cellar/go/1.13.3/libexec/src/encoding/csv/reader.go:202 0x74
main.savePending(0xc00015c1b0, 0x0, 0x0, 0x0)
В чем может быть проблема?
Комментарии:
1. Вы используете
csv.Reader
type одновременно (из основного потока и подпрограммы). Являются ли его методы потокобезопасными?2. ну правильно, думаю, его не сохранить
Ответ №1:
Во время запуска savePending
функции основная подпрограмма продолжает считывать данные с устройства чтения.
Как насчет прерывания цикла for <-sigc
и сохранения остальных:
csvFile, err := os.Open(csvPath)
r := csv.NewReader(csvFile)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
for {
select {
case <-sigc:
savePending(r)
return
default:
}
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Println(record, err)
continue
}
doSomethingWithRecord(record)
}
Комментарии:
1. смотрите также github.com/golang/go/issues/20280 и github.com/jbenet/go-context/blob/master/io/ctxio.go