猿问

io.Reader 可以接受文件描述符吗?“JSON 输入意外结束”

json.Unmarshal将打开的文件描述符从 os.Create() 传递到接受类型 io.Reader 并运行 io.Copy(b.Bytes(), reader) 的函数后,有效 JSON 失败

下面代码块中的方法是否Read()正确实现?io.Reader包装该Read方法,但会向其传递一个打开的文件描述符,将文件读取为字节,从而允许 io.Copy(b.Bytes(), reader) 将数据复制到 var b 中?

有没有更好的方法来做到这一点而不使用ioutil.ReadAll

  1. 已验证 JSON 完全有效。使用 jq 和 3 个在线 JSON 验证器进行验证。

  2. 验证数据实际上已通过另一个实现 io.Write 的函数成功写入文件。

  3. 已验证ioutil.ReadAll可以将 JSON 读取为字节,因此我认为所使用的方法实施不正确。

** 这不是我的代码,我正在对其他人编写的代码进行故障排除,但其他人无法回答任何问题 **

我有一个 json 文件collected_data.json

该文件是使用 os.Create 创建的

file, err := os.Create("/var/log/collected_data.json")

配置了一个结构,将其设置fileDataStore

profiler := &collectors.SystemProfiler{

  DataStore:         file,

  NetworkInterfaces: interfaces,

  ApiURL:            *apiURL,

  RunOnce:           *runOnce,

  SysTag:            *sysTag,

}

然后我们运行一个Gather()方法。


err = profiler.Send(output)

if err != nil {

  log.Error(err)

}

该Send()方法实现了 SystemProfiler 结构:


func (s *SystemProfiler) Send(profile *SystemProfile) error {...}

到此为止,一切工作正常,直到我们尝试从 读取和解组数据的代码部分/var/log/collected_data.json。


在此Send()方法中,我们尝试在两种情况下读取文件/var/log/collected_data.json。


第一,如果文件不为空,我们读取该文件,并用它做一些事情(此处未显示)。


data, err := store.Read(s.DataStore)

if err != nil {

  log.Print("I couldn't read the datastore")

  return err

}

第二,如果文件不为空,我们将数据写入文件,然后立即将其读回并 Unmarshal 以满足稍后在reflect.DeepEqual数据比较和写入文件的数据之间进行比较的函数。


在这两种情况下,该Read()方法都会返回“Unexpected end of JSON input”,并且文件中包含有效的 JSON /var/log/collected_data.json。用于写入数据的方法工作得很好。


{"level":"info","msg":"I couldn't read the datastore","time":"2019-08-02T02:26:42-04:00"}

{"level":"error","msg":"unexpected end of JSON input","time":"2019-08-02T02:26:42-04:00"}

该Read()方法如下所示:


// Read reads JSON data from an io.Reader

func Read(reader io.Reader) (interface{}, error) {

  var data interface{}

  var b bytes.Buffer

  io.Copy(&b, reader)


  err := json.Unmarshal(b.Bytes(), &data)

    if err != nil {

      return nil, err

    }

  return data, nil

}

预期成绩:


有效的 JSON 从 io.Reader 类型的 reader 复制到 bytes.Buffer 类型的 b,成功解组并返回。


实际结果:{"level":"error","msg":"JSON 输入意外结束","time":"2019-08-02T02:26:42-04:00"}


狐的传说
浏览 112回答 1
1回答

暮色呼如

问题的答案是肯定的。An*os.File可以用作io.Reader.问题在于应用程序将数据写入文件,然后尝试从文件中读取相同的数据,而不查找数据写入的位置。通过在调用 store.Write 之后和调用 store.Read 之前添加以下代码来解决此问题。 if _, err := s.DataStore.Seek(io.SeekStart, 0); err != nil {       return err  }
随时随地看视频慕课网APP

相关分类

Go
我要回答