我正在开发一个流式 XML 编码器,它将同时将 XML 写入本地文件和 S3 存储桶。然而,通过测试它写入两个本地文件,我可以看到其中一个文件每次都缺少结束标记。
以下是我的大致做法(省略错误处理):
func copyToFile (fileName string) {
f, _ := os.Create(fileName)
defer f.Close()
io.Copy(f, pr)
}
func main () {
pr, pw := io.Pipe()
defer pw.Close()
encoder := xml.NewEncoder(pw)
go copyToFile("file1.xml")
go copyToFile("file2.xml")
encoder.EncodeToken(xml.StartElement{...})
encoder.Encode(SomeStruct{})
encoder.EncodeToken(xml.EndElement{...})
encoder.Flush()
}
file1.xml
中的结果符合预期,所有标记都正确关闭,但在 file2.xml
中,结束标记(调用 encoder. EncodeToken(xml.EndElement{...})
) 丢失。
我做错了什么?当我将阅读器复制到 S3 时,我可以获得相同的结果吗?
最佳答案
返回的 io.PipeReader
上不能有多个读者,不会为所有读者复制数据。 io.PipeReader
只能“服务”单个读取器,并且您启动 2 个 goroutine 来从中读取数据。
要实现您想要的效果,请使用 io.MultiWriter()
。它会返回一个 io.Writer
到您可以写入的位置,它会将写入复制到您传递给它的所有写入器。
例如:
f1 := &bytes.Buffer{}
f2 := &bytes.Buffer{}
w := io.MultiWriter(f1, f2)
encoder := xml.NewEncoder(w)
encoder.EncodeToken(xml.StartElement{Name: xml.Name{Local: "test"}})
encoder.Encode(image.Point{1, 2})
encoder.EncodeToken(xml.EndElement{Name: xml.Name{Local: "test"}})
encoder.Flush()
fmt.Println(f1)
fmt.Println(f2)
这将输出(在 Go Playground 上尝试):
<test><Point><X>1</X><Y>2</Y></Point></test>
<test><Point><X>1</X><Y>2</Y></Point></test>
上面的示例写入 2 个内存缓冲区。要写入 2 个文件,您可以传递 2 os.File
s到 io.MultiWriter()
(或任何其他实现 io.Writer
):
f1, err := os.Create("file1.xml")
if err != nil {
panic(err)
}
defer f1.Close()
f2, err := os.Create("file2.xml")
if err != nil {
panic(err)
}
defer f2.Close()
w := io.MultiWriter(f1, f2)
// ...
关于Golang中的XML编码器不会关闭所有流中的标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59047594/