如何将结构体编码回字节缓冲区?

huangapple go评论108阅读模式
英文:

How to encode a struct back to a bytes buffer

问题

我正在进行一个API请求,返回的响应是一个bytes.Buffer。然后我将其解码为我的结构体:

resp, status, err := // 调用API的http客户端并返回字节缓冲区

result := MyStruct{}
err = json.NewDecoder(response).Decode(&result)

现在我想要对我的结构体result进行gzip压缩。

我应该使用json解码器来获取值吗?

我想要对解码后的json进行gzip压缩。

此外,我对字节数组、字节缓冲区和这些读取器之间的关系感到困惑。这种层次结构是否类似于Java?

英文:

I am making a API request and the response I get back is a bytes.Buffer.
I then json decode that into my struct:

resp, status, err := // api call that calls http client do and returns byte buff

result := MyStruct{}
err = json.NewDecoder(response).Decode(&result)

I know want to take my struct, result, and gzip it.

Should I be using a json decoder to get the value back?

I want to then take that decoded json so I can then gzip it eventually.

Also, I am confused between a byte array, bytebuffer and then these readers. Is this hierarchy like java?

答案1

得分: 3

如果你想将你的结构体存储为JSON,通常最简单的方法是使用json.Marshal(),例如:

b, err := json.Marshal(&myStruct)

在这种情况下,b将是一个字节切片([]byte)。你可以使用gzip包对其进行压缩。例如,要将字节压缩到文件中,你可以使用以下代码:

f, _ := os.Create("/tmp/s.gz")
defer f.Close()

w := gzip.NewWriter(f)
w.Write(b)
w.Close()

如果你愿意,你可以直接使用json.Encoder.Encode()来避免创建字节切片。

f, _ := os.Create("/tmp/s.gz")
defer f.Close()

w := gzip.NewWriter(f)
json.NewEncoder(w).Encode(&myStruct)
w.Close()

根据你想要存储或发送压缩的JSON的位置,你可以将gzip.NewWriter(f)中的参数f替换为任何实现了io.Writer接口的对象。例如,在处理程序中,你可以直接使用http.ResponseWriter发送压缩的响应:

func MyHandler(w http.ResponseWriter, r *http.Request) {
    myStruct := ...          // 从某处获取结构体
    gz := gzip.NewWriter(w)
    json.NewEncoder(gz).Encode(&myStruct)
    gz.Close()
}
英文:

If you want to store your struct as json, the simplest way is usually to use json.Marshal(), as in:

b, err := json.Marshal(&myStruct)

b will in this case be a byte slice ([]byte). This can later be gzipped using the gzip package. For instance, to gzip the bytes to a file, you could use:

f, _ := os.Create("/tmp/s.gz")
defer f.Close()

w := gzip.NewWriter(f)
w.Write(b)
w.Close()

If you want to, you can bypass creating the byte slice by using json.Encoder.Encode() directly instead.

f, _ := os.Create("/tmp/s.gz")
defer f.Close()

w := gzip.NewWriter(f)
json.NewEncoder(w).Encode(&myStruct)
w.Close()

Depending on where you want to store or send the gzipped json, you can replace the parameter f used in gzip.NewWriter(f) to be any object that implements io.Writer. For instance, you can send the gzipped response using http.ResponseWriter directly in a handler:

func MyHandler(w http.ResponseWriter, r *http.Request) {
    myStruct := ...          // Get struct from somewhere
    gz := gzip.NewWriter(w)
    json.NewEncoder(gz).Encode(&myStruct)
    gz.Close()
}

答案2

得分: 2

我有点困惑你的问题,但也许这可以帮到你一点:

假设你使用标准的http.Client,你可以通过Client.Do方法发起HTTP请求,它会返回一个*http.Response

你可以从Body字段中读取响应体,它的类型是io.ReadCloser。实际上,这只是一个将io.Readerio.Closer接口组合在一起的接口。如果你知道响应是json格式的,你可以使用json.NewDecoder创建一个json.Decoder,它接受任何io.Reader

需要注意的是,所有类型都通过在其上定义以下函数隐式实现了io.Reader

Read(p []byte) (n int, err error)

就像*http.ResponseBody字段是一个io.Reader一样,任何bytes.Buffer都实现了io.Reader,因为它实现了Buffer.Read函数。

相比之下,[]byte(字节数组)是一个标量类型,它本身没有实现任何函数。因此,[]byte不实现io.Reader,所以你不能直接将其传递给json.NewDecoder。如果你想从字节数组/切片解码JSON,你应该使用json.Unmarshal或者使用bytes.NewBuffer将你的[]byte创建为一个bytes.Buffer,然后再将其传递给json.Decoder

对于编码JSON的情况,相同的概念也适用,但这次你需要一个io.Writer和一个json.Encoder,而不是io.Reader

英文:

I am a bit confused by your question but maybe this helps a bit:

Assuming you would use the standard http.Client your HTTP call would be done via Client.Do which returns an *http.Response.

You can read the response body from the Body field which is of type io.ReadCloser. This is actually just an interface that combines the io.Reader and io.Closer interface. If you know the response is json you can now create a json.Decoder using json.NewDecoder which accepts any io.Reader.

Its important to keep in mind that all types implicitly implement io.Reader by having the following function defined on them:

Read(p []byte) (n int, err error)

Just as the *http.Response Body field is an io.Reader any bytes.Buffer implements io.Reader because it implements the Buffer.Read function.

In contrast a []byte (byte array) is a scalar type that does not implement any functions on its own. Therefore []byte does not implement io.Reader so you can not just pass this into json.NewDecoder. If you want to decode JSON from a byte array/slice you should probably just use json.Unmarshal or create a bytes.Buffer from your []byte using bytes.NewBuffer and then again pass that to the json.Decoder.

The same concepts apply for encoding JSON back but this time instead of an io.Reader you need an io.Writer and a json.Encoder.

答案3

得分: 0

io.Readerio.Writer是接口,无论其实现方式如何,都指定了对象的行为。bytes.Buffer是实现了io.Readerio.Writer的数据结构。数组只是核心语言数据结构,类似于其他语言中的数据结构。大多数接口的优势在于,尽管底层实现不同,你仍然可以统一地操作它们。例如,io库中有一个函数func TeeReader(r Reader, w Writer) Reader,它返回一个从r读取并将其写入w的Reader。你可以在读取和解码gzip响应时使用它。

SomeWriter, err := os.OpenFile("some/File", os.O_WRONLY, os.ModePerm) //例如将gzip写入文件
gzipper := gzip.NewWriter(SomeWriter) //但可以是任何Writer
tee := io.TeeReader(response, gzipper)
//然后
err = json.NewDecoder(tee).Decode(&result)
英文:

io.Reader and io.Writer are interfaces specifying object behaviour regardless of it implementation. bytes.Buffer is data structure implementing both io.Reader and io.Writer. array is just core language data structure similar with others languages have. Most interfaces advantage is you can operate with them uniformly despite underlying implementations. For example io library has func TeeReader(r Reader, w Writer) Reader which returns a Reader that writes to w what it reads from r. You can use it to gzip response as you read and decode it.

SomeWriter, err := os.OpenFile("some/File", os.O_WRONLY, os.ModePerm ) //gzip to file for example
gzipper := gzip.NewWriter(SomeWriter) //but can be any Writer
tee := io.TeeReader(response, gzipper)
//and then
err = json.NewDecoder(tee).Decode(&result)

huangapple
  • 本文由 发表于 2016年4月24日 01:56:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/36814394.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定