英文:
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.Reader
和io.Closer
接口组合在一起的接口。如果你知道响应是json
格式的,你可以使用json.NewDecoder
创建一个json.Decoder
,它接受任何io.Reader
。
需要注意的是,所有类型都通过在其上定义以下函数隐式实现了io.Reader
:
Read(p []byte) (n int, err error)
就像*http.Response
的Body
字段是一个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.Reader
和io.Writer
是接口,无论其实现方式如何,都指定了对象的行为。bytes.Buffer
是实现了io.Reader
和io.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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论