读取和解析大型XML文件的性能问题

ami*_*mir 5 xml go

我有一个包含几个大型XML文件的目录(总大小约为10 GB)。有什么方法可以遍历包含XML文件的目录并读取50字节乘50字节并以高性能解析XML文件吗?

func (mdc *Mdc) Loadxml(path string, wg sync.WaitGroup) {
    defer wg.Done()
    //var conf configuration
    file, err := os.Open(path)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    scanner := bufio.NewScanner(file)
    buf := make([]byte, 1024*1024)
    scanner.Buffer(buf, 50)
    for scanner.Scan() {
        _, err := file.Read(buf)
        if err != nil {
            log.Fatal(err)
        }
    }

    err = xml.Unmarshal(buf, &mdc)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(mdc)
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*erg 5

您可以做得更好:您可以标记您的 xml 文件。

假设你有一个像这样的 xml

<inventory>
  <item name="ACME Unobtainium">
    <tag>Foo</tag>
    <count>1</count>
  </item>
  <item name="Dirt">
    <tag>Bar</tag>
    <count>0</count>
  </item>
</inventory>
Run Code Online (Sandbox Code Playgroud)

你实际上可以拥有以下数据模型

type Inventory struct {
    Items []Item `xml:"item"`
}

type Item struct {
    Name  string   `xml:"name,attr"`
    Tags  []string `xml:"tag"`
    Count int      `xml:"count"`
}
Run Code Online (Sandbox Code Playgroud)

现在,您所要做的就是使用filepath.Walk并对要处理的每个文件执行类似的操作:

    decoder := xml.NewDecoder(file)

    for {
        // Read tokens from the XML document in a stream.
        t, err := decoder.Token()

        // If we are at the end of the file, we are done
        if err == io.EOF {
            log.Println("The end")
            break
        } else if err != nil {
            log.Fatalf("Error decoding token: %s", err)
        } else if t == nil {
            break
        }

        // Here, we inspect the token
        switch se := t.(type) {

        // We have the start of an element.
        // However, we have the complete token in t
        case xml.StartElement:
            switch se.Name.Local {

            // Found an item, so we process it
            case "item":
                var item Item

                // We decode the element into our data model...
                if err = decoder.DecodeElement(&item, &se); err != nil {
                    log.Fatalf("Error decoding item: %s", err)
                }

                // And use it for whatever we want to
                log.Printf("'%s' in stock: %d", item.Name, item.Count)

                if len(item.Tags) > 0 {
                    log.Println("Tags")
                    for _, tag := range item.Tags {
                        log.Printf("\t%s", tag)
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

使用虚拟 XML 的工作示例: https: //play.golang.org/p/MiLej7ih9Jt