将os.Create()的打开文件描述符传递给接受类型io.Reader的函数并运行io.Copy(b.Bytes(),reader)后,有效JSON的json.Unmarshal
失败。
以下代码块中的Read()
方法是否正确实现? io.Reader
包装了Read
方法,但是会传递一个打开的文件描述符给它读取字节数据,从而允许io.Copy(b.Bytes(),reader)将数据复制到var b吗?
有没有不使用ioutil.ReadAll
的更好的方法呢?
ioutil.ReadAll
可以将JSON读取为字节,因此我认为所使用的方法实现不正确。 **这不是我的代码,我正在对其他人无法解决的问题编写的代码进行故障排除**
我有一个json文件
collected_data.json
。该文件是使用os.Create创建的
file, err := os.Create("/var/log/collected_data.json")
配置了一个结构,该结构将
file
设置为DataStore
: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()
方法中,我们尝试在2种情况下读取/var/log/collected_data.json
文件。1,如果文件不为空,我们将读取文件并对其进行处理(此处未显示)。
data, err := store.Read(s.DataStore)
if err != nil {
log.Print("I couldn't read the datastore")
return err
}
第二,如果文件不为空,我们将数据写入文件,然后立即将其读回并解组,以满足后来的功能,该功能在比较的数据和写入文件的数据之间执行
reflect.DeepEqual
。在这两种情况下,
Read()
方法都返回“JSON输入的意外结尾”,并在文件/var/log/collected_data.json
中带有有效的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类型的阅读器复制到bytes.Buffer类型的b中,成功将其解组并返回。
实际结果:
{“level”:“错误”,“msg”:“JSON输入的意外结束”,“time”:“2019-08-02T02:26:42-04:00”}
要回答评论中提出的问题,这是
Send()
函数内部的代码块:var storedProfile SystemProfile
check := store.IsEmpty(s.DataStore)
if check == false {
log.Print("Data Store Exists")
// If there is data stored, read it
data, err := store.Read(s.DataStore)
if err != nil {
return err
}
//var tmp SystemProfile
err = mapstructure.Decode(data, &storedProfile)
if err != nil {
return err
}
} else {
log.Print("Data Store Doesn't Exist")
// If the data store is empty, write to it
err := store.Write(s.DataStore, profile)
if err != nil {
return err
}
data, err := store.Read(s.DataStore)
if err != nil {
log.Print("I couldn't read the datastore")
return err
}
err = mapstructure.Decode(data, &storedProfile)
if err != nil {
log.Print("I couldn't decode the json to a map")
return err
}
body, err := json.Marshal(profile)
if err != nil {
return err
}
_, err = client.Post(s.ApiURL, "application/json", bytes.NewBuffer(body)) // TODO: Handle response from API here
log.Print(client.LogString())
}
if !reflect.DeepEqual(storedProfile, profile ) {
// If what's in the data store and what has been collected are different,
// write the recently collected data to the data store and send it out to the API
store.Write(s.DataStore, profile)
body, err := json.Marshal(profile)
if err != nil {
return err
}
_, err = client.Post(s.ApiURL, "application/json", bytes.NewBuffer(body)) // TODO: Handle response from API here
if err != nil {
return err
}
log.Print(client.LogString())
}
最佳答案
这个问题的答案是肯定的。 *os.File
可以用作io.Reader
。
问题在于,应用程序将数据写入文件,然后尝试从文件中读取相同的数据,而无需查找数据的写入位置。
通过在调用store.Write之后和调用store.Read之前添加以下代码来解决此问题。
if _, err := s.DataStore.Seek(io.SeekStart, 0); err != nil {
return err
}
关于go - io.Reader可以接受文件描述符吗? “JSON输入意外结束”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57329333/