如何将大量数据封送到XML

问题描述 投票:1回答:1

我需要通过XML发送大量数据,并且我的Docker容器在执行任务时耗尽内存。有没有办法使用Go逐步编组大型XML文档,并逐步将其写入文件,以最大限度地减少内存使用?

xml go marshalling
1个回答
5
投票

使用xml.Encoder将XML输出流式传输到可能是网络连接(io.Writer)或文件(net.Conn)的os.File。完整的结果不会保留在内存中。

您可以使用Encoder.Encode()将Go值编码为XML。通常,您可以传递任何传递给xml.Marshal()的Go值。

Encoder.Encode()只有在您想要编组的数据准备好在内存中时才有用,这对您来说可能是可行的,也可能是不可行的。例如。如果你想编组一个不能(或不应该)被读入内存的大型列表,这对你来说不是一种拯救。

如果输入数据也不能保存在内存中,那么您可以通过标记和元素构造XML输出。您可以使用Encoder.EncodeToken(),它允许您编写结果XML文档的“部分”。

例如,如果要将大列表写入输出,则可以编写一个开始元素标记(例如<list>),然后逐个编写列表元素(每个元素从数据库或文件中获取,或者由一个动态算法),一旦列表被封送,你可以关闭列表元素标签(</list>)。

这是一个简单的例子,你可以这样做:

type Student struct {
    ID   int
    Name string
}

func main() {
    he := func(err error) {
        if err != nil {
            panic(err) // In your app, handle error properly
        }
    }

    // For demo purposes we use an in-memory buffer,
    // but this may be an os.File too.
    buf := &bytes.Buffer{}

    enc := xml.NewEncoder(buf)
    enc.Indent("", "  ")

    he(enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "list"}}))
    for i := 0; i < 3; i++ {
        // Here you can fetch / construct the records
        he(enc.Encode(Student{ID: i, Name: string(i + 'A')}))
    }
    he(enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "list"}}))
    he(enc.Flush())

    fmt.Println(buf.String())
}

上面的输出是(在Go Playground上试试):

<list>
  <Student>
    <ID>0</ID>
    <Name>A</Name>
  </Student>
  <Student>
    <ID>1</ID>
    <Name>B</Name>
  </Student>
  <Student>
    <ID>2</ID>
    <Name>C</Name>
  </Student>
</list>
© www.soinside.com 2019 - 2024. All rights reserved.