2016-04-23 109 views
1

我正在发出一个API请求,并且我得到的响应是一个bytes.Buffer。 我那么JSON解码是为我的结构:如何将结构编码回字节缓冲区

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

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

我知道要带我的结构,结果,和gzip它。

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

我想然后采取解码的json,所以我可以最终gzip它。

此外,我对字节数组,字节缓冲区和这些读取器之间感到困惑。这个层次结构像java吗?

回答

2

我有点您的问题感到困惑,但也许这有点帮助:

假设你会使用标准的http.Client你的HTTP调用将通过Client.Do返回一个*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.Reader您需要io.Writerjson.Encoder

+0

当使用NewDecoder VS元帅? – Blankman

+0

如果你已经把所有数据都作为'[] byte'',那么我更喜欢使用'json.Marshal'。如果你使用流数据和/或你只需要一个'io.Reader',那么'json.Decoder'就是要走的路。 –

0

io.Readerio.Writer是指定对象行为的接口,不管它的实现如何。 bytes.Buffer是实现io.Readerio.Writer的数据结构。数组只是与其他语言相似的核心语言数据结构。大多数接口的优势在于,尽管有底层实现,但您可以一致地操作它例如,io库有func TeeReader(r Reader, w Writer) Reader,它返回一个读写器,它读写从r读取的内容。您可以使用它在读取和解码时对gzip响应进行解码。

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) 
3

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

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

B就在这种情况下是字节片([]字节) 。这可以稍后使用gzip包进行gzip压缩。例如,为了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() 

根据你要存储或发送gzip压缩JSON,您可以替代gzip.NewWriter(f)曾经是实现io.Writer任何对象的参数f。例如,你可以使用http.ResponseWriter直接在处理器发送gzip压缩的响应:

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