Потоковые данные из ответа на запрос в CSV в go - PullRequest
0 голосов
/ 25 февраля 2020

У меня есть что-то вроде конвейера данных.

Строки ответа API (10k) как JSON. => Очистить некоторые данные в новую структуру => Создать файл CSV

В настоящее время я могу сделать это, получив полный ответ и выполнив это шаг за шагом.

Мне было интересно, есть более простой способ передать ответное чтение сразу в CSV, а также записать в файл, когда он переходит к запросу-ответу.

Текущий код:

У меня будет JSON как { "name": "Full Name", ...( 20 columns)}, и эти данные повторяются около 10-20 тысяч раз с различными значениями.

Для запроса

var res *http.Response
    if res, err = client.Do(request); err != nil {
        return errors.Wrap(err, "failed to perform request")
    }

Для Unmarshal

var record []RecordStruct

if err = json.NewDecoder(res.Body).Decode(&record); err != nil {
        return err
}

Для CSV


var row []byte
    if row, err = csvutil.Marshal(record); err != nil {
        return err
}

1 Ответ

0 голосов
/ 28 февраля 2020

Для потоковой передачи массива объектов JSON необходимо декодировать вложенные объекты вместо объекта root. Для этого вам нужно прочитать данные с помощью токенов ( check Token method ). Согласно документации:

Token возвращает следующий JSON токен во входном потоке. В конце входного потока Token возвращает nil, io.EOF.

Token гарантирует, что возвращаемые им разделители [ ] { } правильно вложены и сопоставлены: если Токен обнаружит неожиданный разделитель во входных данных, он вернет ошибку.

Входной поток состоит из базовых c JSON значений - bool, string, number и null - вместе с разделителями [ ] { } типа Delim для обозначения начала и конца массивов и объектов. Запятые и двоеточия исключаются.

Это означает, что вы можете декодировать документ по частям. Найдите официальный пример, как это сделать здесь

Я опубликую фрагмент кода, который покажет, как вы можете объединить json stream techni c с записью результата в CSV:

package main

import (
    "encoding/csv"
    "encoding/json"
    "log"
    "os"
    "strings"
)

type RecordStruct struct {
    Name string `json:"name"`
    Info string `json:"info"`
    // ... any field you want
}

func (rs *RecordStruct) CSVRecord() []string {
    // Here we form data for CSV writer
    return []string{rs.Name, rs.Info}
}

const jsonData =
    `[
        { "name": "Full Name", "info": "..."},
        { "name": "Full Name", "info": "..."},
        { "name": "Full Name", "info": "..."},
        { "name": "Full Name", "info": "..."},
        { "name": "Full Name", "info": "..."}
    ]`

func main() {
    // Create file for storing our result
    file, err := os.Create("result.csv")
    if err != nil {
        log.Fatalln(err)
    }
    defer file.Close()

    // Create CSV writer using standard "encoding/csv" package
    var w = csv.NewWriter(file)

    // Put your reader here. In this case I use strings.Reader
    // If you are getting data through http it will be resp.Body
    var jsonReader = strings.NewReader(jsonData)

    // Create JSON decoder using "encoding/json" package
    decoder := json.NewDecoder(jsonReader)

    // Token returns the next JSON token in the input stream.
    // At the end of the input stream, Token returns nil, io.EOF.
    // In this case our first token is '[', i.e. array start
    _, err = decoder.Token()
    if err != nil {
        log.Fatalln(err)
    }

    // More reports whether there is another element in the
    // current array or object being parsed.
    for decoder.More() {
        var record RecordStruct
        // Decode only the one item from our array
        if err := decoder.Decode(&record); err != nil {
            log.Fatalln(err)
        }
        // Convert and put out record to the csv file
        if err := writeToCSV(w, record.CSVRecord()); err != nil {
            log.Fatalln(err)
        }
    }

    // Our last token is ']', i.e. array end
    _, err = decoder.Token()
    if err != nil {
        log.Fatalln(err)
    }
}

func writeToCSV(w *csv.Writer, record []string) error {
    if err := w.Write(record); err != nil {
        return err
    }
    w.Flush()
    return nil
}

Вы также можете использовать сторонние пакеты, такие как github.com / bcicen / jstream

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...