2014-01-17 3 views
105

요청시 JSON 페이로드를 인코딩하고 응답에서 JSON 본문을 디코딩해야하는 API 클라이언트를 개발 중입니다.json.Unmarshal 대 json.NewDecoder.Decode를 사용하여 Golang의 JSON 디코딩

여러 라이브러리에서 소스 코드를 읽었으며 필자가 본 것부터는 JSON 문자열을 인코딩하고 디코딩하는 데 기본적으로 두 가지 가능성이 있습니다. 전체 응답 문자열

data, err := ioutil.ReadAll(resp.Body) 
if err == nil && data != nil { 
    err = json.Unmarshal(data, value) 
} 

또는 내 경우에는 json.NewDecoder.Decode

err = json.NewDecoder(resp.Body).Decode(value) 

를 사용하여 전달

사용 json.Unmarshal, 두 번째 버전은 적은 코드를 필요로 할 것, io.Reader를 구현 HTTP 응답을 처리 할 때 그러나 두 가지 모두를 보았으므로 내가 아닌 다른 솔루션을 사용해야하는지에 대한 선호가 있는지 궁금합니다.

또한, the accepted answer from this question

json.Decoder 대신 json.Unmarshal 사용하십시오 말한다.

그러나 그 이유는 언급하지 않았습니다. json.Unmarshal을 사용하지 않는 것이 좋습니다.

+0

이 [GitHub의 당겨 요청 (https://github.com/codegangsta/martini-contrib/pull/84) 인 경우에 사용된다 정렬 화를 호출 대체 json.NewDecoder는 "JSON 디코딩에서 버퍼를 제거합니다." – Matt

+0

그것은 단지 당신이 사용하기에 더 편리한 입력에 달려 있습니다. http://blog.golang.org/json-and-go에는 두 가지 기술을 모두 사용하는 예가 나와 있습니다. – rexposadas

+12

IMO,'ioutil.ReadAll'은 * 거의 * 항상 잘못된 행동입니다.그것은 당신의 목표와 관련이 없지만 JSON의 마지막 20TB가 마지막'}'이후에 있더라도 파이프를 내려갈 수있는 것을 저장하기에 충분한 인접 메모리가 필요합니다. – Dustin

답변

134

정말 입력 내용에 따라 다릅니다. Decode 메소드의 구현을 json.Decoder으로 보면, 전체 JSON 값을 Go 값으로 언 마샬링하기 전에 메모리에 버퍼링합니다. 따라서 대부분의 경우 메모리가 더 이상 효율적이지는 않습니다 (언어의 향후 버전에서 쉽게 변경 될 수 있음).

그래서 엄지 손가락의 좋은 규칙은 이것이다 :

  • 사용 json.Decoder 데이터가 io.Reader 스트림에서 오는, 또는 데이터 스트림에서 여러 값을 해독해야하는 경우.
  • 이미 메모리에 JSON 데이터가있는 경우 json.Unmarshal을 사용하십시오.

HTTP 요청에서 읽는 경우 분명히 스트림에서 읽고 있으므로 json.Decoder을 선택합니다.

+20

또한 Go 1.3 소스 코드를 검사하여 json.Encoder를 사용하는 경우 인코딩에 대해 배울 수 있습니다.이 스크립트는 새로운 sync.Pool이 지원하는 글로벌 버퍼 풀을 재사용합니다. 당신이 많은 json을 인코딩한다면. 저기 하나의 글로벌 수영장 그래서 다른 json.Encoder의 공유 그것 뿐이야. json.Marshal 인터페이스에서이 작업을 수행 할 수없는 이유는 바이트가 사용자에게 반환되고 사용자가 바이트를 풀에 "반환"할 방법이 없기 때문입니다. 그래서 인코딩을 많이한다면 json.Marshal은 항상 약간의 버퍼 변동이 있습니다. – Aktau

+0

@Flimzy : 정말입니까? 소스 코드는 여전히 디코딩 전에 버퍼로 전체 값을 읽습니다. https://github.com/golang/go/blob/master/src/encoding/json/stream.go#L56-L62. 'Buffered' 메쏘드는 값 뒤에있는 내부 버퍼에 읽혀진 여분의 데이터를 볼 수있게 해줍니다. –

+0

@JamesHenstridge : 아니, 당신 말이 맞을 것입니다. 나는 성명서를 의도 한 것과 다르게 해석하고있었습니다. 혼란에 사과드립니다. – Flimzy

-4

디코딩 전에 파이프에서 [] 바이트를 가져와야하므로 HTTP 연결을 처리 할 때 io에서 읽어야하므로 두 함수가 동일하다고 생각합니다. 그러나 데이터가 메모리에 저장되었거나 [] 바이트를 얻은 경우 Unmarshal을 직접 사용할 수 있습니다. 더 좋습니다.

json.Decoder은 HTTP 연결, 웹 소켓 또는 파일을 읽고 쓸 때 사용됩니다.

json.Unmarshal는 입력 [] 바이트