Golang中gob.Decode和Encode的疑难问题求助

Golang中gob.Decode和Encode的疑难问题求助 大家好,这是我第一次在论坛发帖。

我想将一些结构体写入二进制文件,经过搜索,我找到了以下两个函数来实现这个功能。

func writeGob(path string, object interface{}, offset int64) error {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0777)

	if err != nil {
		PrintError("Error intentando abrir el archivo")
		return errors.New("Error intentado abrir el archivo")
	}

	file.Seek(offset, 0)
	encoder := gob.NewEncoder(file)
	encoder.Encode(object)
	file.Close()
	return err

}

func readGob(path string, offset int64, object interface{}) error {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 666)
	if err != nil {
		PrintError("Error intentando abrir el archivo: " + err.Error())
		return errors.New("Error intentando abrir el archivo")
	}

	file.Seek(offset, 0)
	decoder := gob.NewDecoder(file)

	err = decoder.Decode(object)

	file.Close()
	return err // must be nil
}

这是我正在使用的两个结构体。

type Ebr struct {
	PartStatus uint8
	PartFit    uint8
	PartStart  int64
	PartSize   int64
	PartName   [16]uint8
	PartNext   int64
}

type Mbr struct {
	MbrTamanio       int64
	MbrFechaCreacion [20]uint8
	MbrDiskSignature int64
	DiskFit          uint8
	MbrPartition     [4]Partition
}

简单来说,这是一个为大学作业实现的微型 ext2 文件系统。

一切进展顺利,直到我尝试读取一个 Ebr 结构体时遇到了以下错误:

gob: Duplicate types received

这是发生错误的代码行。

var ebr = new(Ebr)
err := readGob(c.Args["path"].(string), ext.PartStart, ebr)

我在谷歌上搜索了这个错误,但没有找到任何帮助。所以,如果你能帮助我,我将非常感激。


更多关于Golang中gob.Decode和Encode的疑难问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

感谢您的回复。我一直在调试,偏移量似乎是相同的。我进行了一些测试,先写入EBR,然后立即读取,一切正常。但是,如果尝试从代码的另一部分读取它,就会出现错误。

更多关于Golang中gob.Decode和Encode的疑难问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


ext.PartStart

您很可能从错误的偏移量开始读取,导致 gob 内部机制误解了它试图解码的内容。

// 代码示例(如有)应放置于此

这个错误通常发生在多次调用 gob.Decode() 时,解码器遇到重复注册的类型定义。Gob 需要在编解码双方注册相同的类型,但多次注册会导致此错误。

在你的代码中,每次调用 readGob() 都会创建新的解码器,但文件可能包含多个 gob 数据。当解码器遇到已经注册过的类型时,就会报 “Duplicate types received” 错误。

以下是修复方案:

import (
    "bytes"
    "encoding/gob"
    "os"
)

// 在 init 函数中注册类型,确保只注册一次
func init() {
    gob.Register(Ebr{})
    gob.Register(Mbr{})
    gob.Register(Partition{}) // 如果 Partition 是自定义类型也需要注册
}

func writeGob(path string, object interface{}, offset int64) error {
    file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0777)
    if err != nil {
        return err
    }
    defer file.Close()

    _, err = file.Seek(offset, 0)
    if err != nil {
        return err
    }

    encoder := gob.NewEncoder(file)
    return encoder.Encode(object)
}

func readGob(path string, offset int64, object interface{}) error {
    file, err := os.OpenFile(path, os.O_RDONLY, 0666)
    if err != nil {
        return err
    }
    defer file.Close()

    _, err = file.Seek(offset, 0)
    if err != nil {
        return err
    }

    // 使用缓冲读取器避免重复类型问题
    var buf bytes.Buffer
    _, err = buf.ReadFrom(file)
    if err != nil {
        return err
    }

    decoder := gob.NewDecoder(&buf)
    return decoder.Decode(object)
}

如果文件包含多个连续的 gob 数据,应该使用同一个解码器连续解码:

func readMultipleGobs(path string) error {
    file, err := os.Open(path)
    if err != nil {
        return err
    }
    defer file.Close()

    decoder := gob.NewDecoder(file)
    
    // 读取第一个结构
    var mbr Mbr
    if err := decoder.Decode(&mbr); err != nil {
        return err
    }
    
    // 读取第二个结构(使用同一个解码器)
    var ebr Ebr
    if err := decoder.Decode(&ebr); err != nil {
        return err
    }
    
    return nil
}

对于你的具体使用场景,确保在程序启动时注册所有相关类型,并且对于包含多个 gob 数据的文件,使用同一个解码器实例进行连续解码。

回到顶部