Go

2016-12-23 3 views
0

을 사용하여 JSON 파일에서 하나의 값을 읽는 방법 Go에 프로그래밍을 처음 접했을 때 매우 분명한 사실을 사과드립니다. 나는 foo.json라는 JSON 파일이 :Go

{"type":"fruit","name":"apple","color":"red"} 

내가 JSON 파일의 "이름"값이 "사과"때 뭔가를하고있는 Go 프로그램을 쓰고 있어요. 해당 파일은 코드의 다른 영역에서 전혀 다른 용도로 사용되기 때문에 JSON 파일의 다른 정보는 필요하지 않습니다.

Decode() 및 Unmarshal()에 대한 설명서를 읽었으며 전체 파일을 구조로 읽는 방법을 설명하는 30 개의 다른 웹 페이지가 있지만 모두 작성하기 만하면됩니다. 올바른 코드는 다음 의사 코드의 첫 번째 두 라인을 구현 : 나는 문자열 값 apple을 포함 name라는 Go 변수로 끝날

file, _ := os.Open("foo.json") 
name = file["name"] 
if (name == "apple") { 
    do stuff 
} 

하도록. Go에서이 작업을 수행하는 올바른 방법은 무엇입니까?

답변

2

당신이 원하는 것은 구조체로 디코딩하는 가장 쉬운 방법 . 형식을 제공

당신의 다른 옵션은 gabs 또는 jason 같은 타사 라이브러리를 사용하는 것입니다 {"type":"fruit","name":"apple","color":"red"}

type Name struct { 
    Name string `json:"name"` 
} 

var data []byte 
data, _ = ioutil.ReadFile("foo.json") 

var str Name 
_ = json.Unmarshal(data, &str) 

if str.Name == "apple" { 
    // Do Stuff 
} 

유사 남아있다.

GABS :

jsonParsed, err := gabs.ParseJSON(data) 
name, ok := jsonParsed.Path("name").Data().(string) 

제이슨 :

v, _ := jason.NewObjectFromBytes(data) 
name, _ := v.GetString("name") 

업데이트 :

구조

type Name struct { 
    Name string `json:"name"` 
} 

은 json에 해당하는 {"name":"foo"}입니다.

따라서 형식이 다른 다음 json에서는 비 정렬 화가 작동하지 않습니다.

[{"name":"foo"}] 

{"bar":{"name":"foo"}} 

추 신 : W.K.S에 언급 된. 귀하의 경우에는 구조체를 사용하지 않으므로 익명 구조체로 충분합니다.

+1

명시 적으로'data'를 선언 할 필요는 없습니다. 또한 출력이 하나 뿐이므로 ('json.Unmarshal()'의 'err') 오류를 무시하기로 결정한 경우 출력을 할당 할 필요가 없습니다. –

+0

응답 해 주셔서 감사합니다.'포맷이 비슷하다면 ... '이라고 말할 때, 비슷한 형태가되어 코드가 깨지는 사례는 무엇인가? –

+0

@EdMorton 죄송합니다, 크리스마스를 위해 아니했습니다. 업데이트 됨. –

1

하나는 파일을 읽고 다른 하나는 json 문서를 읽거나 디코딩합니다. 나는 당신에게 두 가지 일을하는 완전한 모범을 남깁니다.

package main 

import (
    "encoding/json" 
    "io/ioutil" 
    "log" 
    "os" 
) 

func main() { 
    f, err := os.Open("file.json") // file.json has the json content 
    if err != nil { 
     log.Fatal(err) 
    } 

    bb, err := ioutil.ReadAll(f) 
    if err != nil { 
     log.Fatal(err) 
    } 

    doc := make(map[string]interface{}) 
    if err := json.Unmarshal(bb, &doc); err != nil { 
     log.Fatal(err) 
    } 

    if name, contains := doc["name"]; contains { 
     log.Printf("Happy end we have a name: %q\n", name) 
    } else { 
     log.Println("Json document doesn't have a name field.") 
    } 

    log.Printf("full json: %s", string(bb)) 
} 

https://play.golang.org/p/0u04MwwGfn

+0

감사합니다. 나는 여기에 제안 된 3 가지 다른 접근 방법에 대해 좀 더 알아 내려고 노력하고있다. (인터페이스로 디코딩하기 위해 (http://stackoverflow.com/a/41294843/1745001 및 http://stackoverflow.com/a/41295594/ 1745001) 또는 명명 된 구조체 (http://stackoverflow.com/a/41296043/1745001) 또는 명명되지 않은 구조체 (http://stackoverflow.com/a/41296207/1745001)를 참조하십시오. 테스트. –

+0

모든 도움을 주셔서 감사합니다. 결국에는 명명 된 구조 접근 방식을 사용했는데, 이는 제가 작업중인 제품의 다른 코드에서의 컨벤션 일 것입니다. –

1

나는 또한 PHP에서 간단한 솔루션 등 $d = json_decode($json, true)을 찾기 위해 노력하고있다 : 그것을 실행하려면 당신은 당신의 코드 또는 실행 파일의 같은 디렉토리에 file.json라는 파일이 있어야 Golang에서 그런 간단한 방법이 없다는 결론에 도달했습니다.

  • file는 JSON 문자열의 바이트 배열이다

    var f interface{} 
    err = json.Unmarshal(file, &f) 
    
    m := f.(map[string]interface{}) 
    if (m["name"] == "apple") { 
        // Do something 
    } 
    

  • f 인터페이스 제공 다음은 I가 (검사는 명료성을 위해 생략되어있다)을 할 수있는 가장 간단한 해결책 알 수없는 JSON 구조의 일반 컨테이너로
  • mtype assertion이 반환하는지도입니다.

Unmarshal() 어떤 JSON 입력을위한 해당 유형의 변수를 기반으로하기 때문에 우리는 f 문자열의지도라고 주장 할 수 있습니다. 적어도 뭔가 다른 것을 돌려 줄 수는 없었습니다. run-time reflection 의해 변수의 타입을 검출 할 수있다 : 상기 f 변수

fmt.Printf("Type of f = %s\n", reflect.TypeOf(f)) 

Type of f = map[string]interface {} 코드를 출력한다.

그리고 이것은 필요한 검사와 전체 코드입니다 :

package main 

import (
    "fmt" 
    "os" 
    "io/ioutil" 
    "encoding/json" 
) 

func main() { 
    // Read entire file into an array of bytes 
    file, err := ioutil.ReadFile("foo.json") 
    if (err != nil) { 
    fmt.Fprintf(os.Stderr, "Failed read file: %s\n", err) 
    os.Exit(1) 
    } 

    var f interface{} 
    err = json.Unmarshal(file, &f) 
    if (err != nil) { 
    fmt.Fprintf(os.Stderr, "Failed to parse JSON: %s\n", err) 
    os.Exit(1) 
    } 

    // Type-cast `f` to a map by means of type assertion. 
    m := f.(map[string]interface{}) 
    fmt.Printf("Parsed data: %v\n", m) 

    // Now we can check if the parsed data contains 'name' key 
    if (m["name"] == "apple") { 
    fmt.Print("Apple found\n") 
    } 
} 

출력

Parsed data: map[type:fruit name:apple color:red] 
Apple found 

+0

모든 도움을 주셔서 감사합니다. 결국에는 명명 된 구조 접근 방식을 사용했는데, 이는 제가 작업중인 제품의 다른 코드에서의 컨벤션 일 것입니다. –

1

이 작업을 수행하는 올바른 방법은 필요한 필드 만 포함하는 익명 구조체의 인스턴스로 디코딩하는 것입니다. 또한

Playground Link

func main() { 
    myStruct := struct{ Name string }{} 
    json.Unmarshal([]byte(`{"type":"fruit","name":"apple","color":"red"}`), &myStruct) 
    fmt.Print(myStruct.Name) 
} 

, 당신은 Jeffails/gabs JSON 파서를 사용할 수 있습니다 응답에 대한

jsonParsed,_ := gabs.ParseJSON([]byte(`{"type":"fruit","name":"apple","color":"red"}`)); 
value, ok = jsonParsed.Path("name").Data().(string) 
+0

응답 해 주셔서 감사합니다. 디코딩 할 수있는 3 가지 옵션이있는 것 같습니다. - 인터페이스 (http://stackoverflow.com/a/41294843/1745001 및 http://stackoverflow.com/a/41295594/1745001), 명명 된 구조체 (http : // (http://stackoverflow.com/a/41296207/1745001). 가능한 코드 간결성을 뛰어 넘는 접근법에 찬성/반대 의견이 있습니까? –

+0

귀하의 요구 사항에 따라 달라질 수 있습니다. 인터페이스에 대한 디코딩은 예를 들어 웹 API가받은 요청 매개 변수에 따라 다른 json 구조를 반환 할 때 의미가 있습니다. json 구조가 알려지면 구조체가 더 합리적입니다. json 구조가 응용 프로그램의 엔터티에 직접 매핑 될 때 명명 된 구조체가 바람직합니다. 반면에 json이 엔티티를 나타내지 않고 몇 가지 필드 (예 : 질문 에서처럼)의 값을 읽는 것만으로 익명 구조체이면 충분합니다. –

+0

감사합니다. 그것은 무명의 구조체처럼 내 경우 (드물게 변경 구성 파일을 읽고)이 일을하는 방법이 될 것 같은데. 이제 테스트하는 중입니다 ... –

관련 문제