写入 []byte 到文件中导致生成了一个大小为零的文件。

huangapple go评论66阅读模式
英文:

Go. Writing []byte to file results in zero byte file

问题

我试图将结构化数据序列化到文件中。我查看了一些示例,并创建了以下结构:

func (order Order) Serialize(folder string) {
    b := bytes.Buffer{}
    e := gob.NewEncoder(&b)
    err := e.Encode(order)
    if err != nil { panic(err) }

    os.MkdirAll(folder, 0777)
    file, err := os.Create(folder + order.Id)
    if err != nil { panic(err) }
    defer file.Close()


    writer := bufio.NewWriter(file)
    n, err := writer.Write(b.Bytes())

    fmt.Println(n)

    if err != nil {
        panic(err)
    }
}

Serialize 是一个将对象序列化到文件中的方法,通过它的 id 属性调用。我查看了调试器 - 字节缓冲区在写入之前包含数据。我的意思是对象已经完全初始化。即使表示写入字节数的 n 变量超过一千 - 文件也不应该是空的。文件被创建了,但是完全为空。有什么问题吗?

英文:

I try to serialize a structured data to file. I looked through some examples and made such construction:

func (order Order) Serialize(folder string) {
	b := bytes.Buffer{}
	e := gob.NewEncoder(&b)
	err := e.Encode(order)
	if err != nil { panic(err) }

	os.MkdirAll(folder, 0777)
	file, err := os.Create(folder + order.Id)
	if err != nil {  panic(err)	}
	defer file.Close()


	writer := bufio.NewWriter(file)
	n, err := writer.Write(b.Bytes())

	fmt.Println(n)

	if err != nil {
		panic(err)
	}
}

Serialize is a method serializing its object to file called by it's id property. I looked through debugger - byte buffer contains data before writing. I mean object is fully initialized. Even n variable representing quantity of written bytes is more than a thousand - the file shouldn't be empty at all. The file is created but it is totally empty. What's wrong?

答案1

得分: 4

bufio.Writer(正如包名所示)使用缓冲区来缓存写入操作。如果你使用它,必须在完成写入操作后调用Writer.Flush()来确保缓冲数据被写入底层的io.Writer

另外请注意,你可以直接向os.File写入,无需创建一个“包装”它的缓冲写入器(*os.File实现了io.Writer)。

还要注意,你可以直接将gob.Encoder创建为指向os.File的,因此bytes.Buffer是不必要的。

此外,os.MkdirAll()可能会失败,请检查其返回值。

另外,最好使用filepath.Join()来“连接”文件路径的各个部分,它会处理文件夹名称末尾的额外斜杠或缺失斜杠的情况。

最后,最好通过返回一个error值来表示Serialize()的失败,这样调用方有机会检查操作是否成功,并采取相应的措施。

因此,Order.Serialize()应该如下所示:

func (order Order) Serialize(folder string) error {
    if err := os.MkdirAll(folder, 0777); err != nil {
        return err
    }

    file, err := os.Create(filepath.Join(folder, order.Id))
    if err != nil {
        return err
    }
    defer file.Close()

    if err := gob.NewEncoder(file).Encode(order); err != nil {
        return err
    }

    return nil
}
英文:

bufio.Writer (as the package name hints) uses a buffer to cache writes. If you ever use it, you must call Writer.Flush() when you're done writing to it to ensure the buffered data gets written to the underlying io.Writer.

Also note that you can directly write to an os.File, no need to create a buffered writer "around" it. (*os.File implements io.Writer).

Also note that you can create the gob.Encoder directly directed to the os.File, so even the bytes.Buffer is unnecessary.

Also os.MkdirAll() may fail, check its return value.

Also it's better to "concatenate" parts of a file path using filepath.Join() which takes care of extra / missing slashes at the end of folder names.

And last, it would be better to signal the failure of Serialize(), e.g. with an error return value, so the caller party has the chance to examine if the operation succeeded, and act accordingly.

So Order.Serialize() should look like this:

func (order Order) Serialize(folder string) error {
	if err := os.MkdirAll(folder, 0777); err != nil {
		return err
	}

	file, err := os.Create(filepath.Join(folder, order.Id))
	if err != nil {
		return err
	}
	defer file.Close()

	if err := gob.NewEncoder(file).Encode(order); err != nil {
		return err
	}

	return nil
}

huangapple
  • 本文由 发表于 2017年2月21日 21:01:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/42368063.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定