csv 如何写入内存中的文件,然后通过HTTP发送,而不使用中间文件?

z18hc3ub  于 2023-06-19  发布在  其他
关注(0)|答案(2)|浏览(112)

我需要请求、处理数据并将其格式化为CSV,然后根据请求通过Web服务发送它们。
假设请求和处理的数据在下面的data中,我设法使用中间临时文件做到这一点:

package main

import (
    "encoding/csv"
    "io/ioutil"
    "net/http"
    "os"
    "strconv"

    "github.com/go-chi/chi/v5"
)

type Data struct {
    Name string
    Age  int
}

func main() {
    data := []Data{
        {"John", 30},
        {"Jane", 20},
    }
    tempFileName := "temp.csv"
    // create temporary intermediate file
    file, err := os.Create(tempFileName)
    defer file.Close()
    if err != nil {
        panic(err)
    }
    w := csv.NewWriter(file)
    var csvData [][]string
    for _, record := range data {
        row := []string{record.Name, strconv.Itoa(record.Age)}
        csvData = append(csvData, row)
    }
    w.WriteAll(csvData)

    // read temporary intermediate file to send it via HTTP
    fileBytes, err := ioutil.ReadFile(tempFileName)
    if err != nil {
        panic(err)
    }
    // send the file on request
    router := chi.NewRouter()
    router.Get("/data", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/octet-stream")
        w.WriteHeader(http.StatusOK)
        w.Write(fileBytes)
    })
    http.ListenAndServe(":8087", router)
}

请求成功:

PS C:\temp> wget http://localhost:8087/data
--2023-06-13 15:34:00--  http://localhost:8087/data
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:8087... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16 [application/octet-stream]
Saving to: 'data'

data                          100%[=================================================>]      16  --.-KB/s    in 0s

2023-06-13 15:34:00 (523 KB/s) - 'data' saved [16/16]

PS C:\temp> cat data
John,30
Jane,20

到目前为止一切顺利-现在我想摆脱中间文件

  • 使用存储器中的“容器”存储要写入的CSV数据
  • 将其内容以字节形式写入HTTP写入器

我仍然没有很好的理解如何使用io.*bufio.*登陆所需的类型:

  • csv.NewWriter()需要一个*os.File并返回一个*csv.Writer
  • 这个*csv.Writer内容需要以某种方式提取为byte...
  • ...为了给http.ResponseWriter.Write()

处理不同类型的内存中文件操作问题的一般机制(以及特定于这种情况的机制)是什么?

ykejflvf

ykejflvf1#

csv.NewWriter接受一个io.Writer,因此您可以将http.ResponseWriter的示例传递给它,而无需将内容写入文件或内存。
下面是演示:

package main

import (
    "encoding/csv"
    "fmt"
    "net/http"
    "strconv"

    "github.com/go-chi/chi/v5"
)

type Data struct {
    Name string
    Age  int
}

func main() {
    router := chi.NewRouter()
    router.Get("/data", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/octet-stream")
        w.WriteHeader(http.StatusOK)
        data := []Data{
            {"John", 30},
            {"Jane", 20},
        }
        csvWriter := csv.NewWriter(w)
        var csvData [][]string
        for _, record := range data {
            row := []string{record.Name, strconv.Itoa(record.Age)}
            csvData = append(csvData, row)
        }
        if err := csvWriter.WriteAll(csvData); err != nil {
            // handle the error
            fmt.Println(err)
        }
    })
    http.ListenAndServe(":8087", router)
}
e0bqpujr

e0bqpujr2#

感谢JimB的评论(使用bytes.Buffer)以及an answer关于使用指向Buffer的指针)我设法摆脱了临时文件:

package main

import (
    "bytes"
    "encoding/csv"
    "net/http"
    "strconv"

    "github.com/go-chi/chi/v5"
)

type Data struct {
    Name string
    Age  int
}

func main() {
    data := []Data{
        {"John", 30},
        {"Jane", 20},
    }
    var file bytes.Buffer
    w := csv.NewWriter(&file)
    var csvData [][]string
    for _, record := range data {
        row := []string{record.Name, strconv.Itoa(record.Age)}
        csvData = append(csvData, row)
    }
    w.WriteAll(csvData)

    // send the file on request
    router := chi.NewRouter()
    router.Get("/data", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/octet-stream")
        w.WriteHeader(http.StatusOK)
        w.Write(file.Bytes())
    })
    http.ListenAndServe(":8087", router)
}

更好的答案是Zeke Lu's one

相关问题