【问题标题】:Read json object from stdin in golang从 golang 中的标准输入读取 json 对象
【发布时间】:2018-06-26 05:30:58
【问题描述】:

如何从标准输入读取 json 对象? 我想将一个 json 对象复制并粘贴到标准输入中,读取它并解组它。 代码如下:

    var input string
    _, err := fmt.Scan(&input)
    if err != nil {
        fmt.Println(err)
        continue
    }

    var record MedicalRecord
    if err := json.Unmarshal([]byte(input), &record); err != nil {
        log.Println(err)
        continue
    }

错误会打印到控制台。

> 2018/06/26 00:26:32 invalid character ':' after top-level value
> 2018/06/26 00:26:32 unexpected end of JSON input
> 2018/06/26 00:26:32 invalid character ':' after top-level value
> 2018/06/26 00:26:32 invalid character ',' after top-level value
> 2018/06/26 00:26:32 invalid character ':' after top-level value
> 2018/06/26 00:26:32 invalid character ',' after top-level value
> 2018/06/26 00:26:32 invalid character ':' after top-level value
> 2018/06/26 00:26:32 invalid character ',' after top-level value
> 2018/06/26 00:26:32 invalid character ':' after top-level value
> 2018/06/26 00:26:32 invalid character ',' after top-level value

如果我没记错的话,Go 正在读取直到找到 '\n' 。我该如何解决这个问题?

【问题讨论】:

    标签: json string go stdin


    【解决方案1】:

    使用*json.Decoder 来使用来自 io.Reader 的 JSON:

    package main
    
    import (
        "encoding/json"
        "log"
        "os"
    )
    
    type MedicalRecord struct{}
    
    func main() {
        var record MedicalRecord
    
        err := json.NewDecoder(os.Stdin).Decode(&record)
        if err != nil {
            log.Fatal(err)
        }
    }
    

    您可以通过重复调用 Decode 来消费多个连续的 JSON 文档:

    package main
    
    import (
        "encoding/json"
        "io"
        "log"
        "os"
    )
    
    type MedicalRecord struct{}
    
    func main() {
        var record MedicalRecord
    
        dec := json.NewDecoder(os.Stdin)
        for {
            err := dec.Decode(&record)
            if err == io.EOF {
                return
            }
            if err != nil {
                log.Fatal(err)
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      当您调用 json.Unmarshal 时,您应该拥有完整的 JSON 对象,否则您只是试图解组一些对解析器没有意义的部分对象。

      • 从标准输入读取到足够大的缓冲区以容纳整个 JSON 对象。
      • 解组 JSON 对象

      例如:

      package main
      
      import (
          "bytes"
          "io"
          "fmt"
          "os"
          "bufio"
          "encoding/json"
      )
      
      
      func main() {
      
          var buf bytes.Buffer
          reader := bufio.NewReader(os.Stdin)
      
          for {
              line, err := reader.ReadString('\n')
              if err != nil {
                  if err == io.EOF {
                      buf.WriteString(line)
                      break // end of the input
                  } else {
                      fmt.Println(err.Error())
                      os.Exit(1) // something bad happened
                  }   
              }   
              buf.WriteString(line)
      
          }   
      
          fmt.Printf("valid json? %v\n", json.Valid(buf.Bytes()))
      
          type MedicalRecord struct {
              Name string `json:"name"`
              Age int `json:"age"`
          }   
      
          var record MedicalRecord
          err := json.Unmarshal(buf.Bytes(), &record)
          if err != nil {
              fmt.Println(err.Error())
              os.Exit(1) // something bad happened
          }   
      
          fmt.Printf("name: %s, age: %d\n", record.Name, record.Age)
      }
      

      【讨论】:

      • 如果 bufio.NewReader(file) 被 bufio.NewReader(os.Stdin) 替换,goroutine 被阻塞。
      • 我清理了代码以显示完整的工作程序。如果你需要启动一个单独的 goroutine,你必须自己做。
      最近更新 更多