在go中将请求响应中的数据流传输到CSV中



我有一个类似于数据管道的东西。

API响应(10k(行为JSON。=>将部分数据整理为新结构=>创建CSV文件

我目前可以通过得到完整的回应并一步一步地做到这一点。

我想知道是否有一种更简单的方法可以将响应立即流式传输到CSV中,并在处理请求-响应时写入文件。

当前代码:

我将有一个类似于{ "name": "Full Name", ...( 20 columns)}的JSON,该数据以不同的值重复大约10-20k次。

请求

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

对于解组

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
}

要流式传输JSON对象数组,必须解码嵌套对象而不是根对象。要做到这一点,您需要使用令牌读取数据(请查看Token方法(。根据文件:

Token返回输入流中的下一个JSON令牌。在输入流的末尾,Token返回nilio.EOF

Token保证它返回的分隔符[]{}正确嵌套和匹配:如果Token在输入中遇到意外的分隔符,它将返回错误。

输入流由基本的JSON值(bool、string、number和null(以及Delim类型的分隔符[]{}组成,用于标记数组和对象的开始和结束。省略逗号和冒号。

这意味着您可以逐个解码文档。在这里找到一个官方的例子

我将发布一个代码片段,展示如何将json流技术与将结果写入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 这样的3d派对软件包

最新更新