簡體   English   中英

Spring Jaxb2:如何在不讀取內存的情況下將批處理數據追加到XML文件?

[英]Spring Jaxb2: How to append batch data to XML file with no reading it to memory?

我需要將數據批量寫入xml。

有以下域對象:

@XmlRootElement(name = "country")
public class Country {
    @XmlElements({@XmlElement(name = "town", type = Town.class)})
    private Collection<Town> towns = new ArrayList<>();
    ....
}

和:

@XmlRootElement(name = "town")
public class Town {
    @XmlElement
    private String townName;
    // etc
}

我正在用Jaxb2編組對象。 配置如下:

marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(Country.class, Town.class);

因為簡單的封送在這里不能作為marhaller.marshall(fileName, country) -它使xml格式錯誤。

有沒有一種方法可以讓tweek marhaller生成一個文件,如果它不與所有已封裝的數據一起存在,或者僅將其附加在xml文件的末尾,則可以創建文件?

另外,由於此文件可能很大,因此我不想讀取內存中的整個文件,不要追加數據,然后再寫入磁盤。

我已經使用StAX進行xml處理,因為它基於流,比DOM消耗更少的內存,並且與只能解析xml數據但不能寫入xml的SAX相比,具有讀取和寫入的能力。

這是我想出的方法:

public enum StAXBatchWriter {
    INSTANCE;
    private static final Logger LOGGER = LoggerFactory.getLogger(StAXBatchWriter.class);

    public void writeUrls(File original, Collection<Town> towns) {
        XMLEventReader eventReader = null;
        XMLEventWriter eventWriter = null;
        try {
            String originalPath = original.getPath();
            File from = new File(original.getParent() + "/old-" + original.getName());
            boolean isRenamed = original.renameTo(from);
            if (!isRenamed)
                throw new IllegalStateException("Failed to rename file: " + original.getPath() + " to " + from.getPath());
            File to = new File(originalPath);

            XMLInputFactory inFactory = XMLInputFactory.newInstance();
            eventReader = inFactory.createXMLEventReader(new FileInputStream(from));

            XMLOutputFactory outFactory = XMLOutputFactory.newInstance();
            eventWriter = outFactory.createXMLEventWriter(new FileWriter(to));

            XMLEventFactory eventFactory = XMLEventFactory.newInstance();

            while (eventReader.hasNext()) {
                XMLEvent event = eventReader.nextEvent();
                eventWriter.add(event);
                if (event.getEventType() == XMLEvent.START_ELEMENT && event.asStartElement().getName().toString().contains("country")) {
                    for (Town town : towns) {
                        writeTown(eventWriter, eventFactory, town);
                    }
                }
            }
            boolean isDeleted = from.delete();
            if (!isDeleted)
                throw new IllegalStateException("Failed to delete old file: " + from.getPath());
        } catch (IOException | XMLStreamException e) {
            LOGGER.error(e.getMessage(), e);
            throw new RuntimeException(e);
        } finally {
            try {
                if (eventReader != null)
                    eventReader.close();
            } catch (XMLStreamException e) {
                LOGGER.error(e.getMessage(), e);
            }
            try {
                if (eventWriter != null)
                    eventWriter.close();
            } catch (XMLStreamException e) {
                LOGGER.error(e.getMessage(), e);
            }
        }
    }

    private void writeTown(XMLEventWriter eventWriter, XMLEventFactory eventFactory, Town town) throws XMLStreamException {
        eventWriter.add(eventFactory.createStartElement("", null, "town"));

        // write town id
        eventWriter.add(eventFactory.createStartElement("", null, "id"));
        eventWriter.add(eventFactory.createCharacters(town.getId()));
        eventWriter.add(eventFactory.createEndElement("", null, "id"));

        //write town name
        if (StringUtils.isNotEmpty(town.getName())) {
            eventWriter.add(eventFactory.createStartElement("", null, "name"));
            eventWriter.add(eventFactory.createCharacters(town.getName()));
            eventWriter.add(eventFactory.createEndElement("", null, "name"));
        }

        // write other fields

        eventWriter.add(eventFactory.createEndElement("", null, "town"));
    }
}

這不是最好的方法,盡管它基於流並且可以工作,但它有一些開銷。 當添加批次時-必須重新讀取舊文件。

可以選擇在文件的某個位置附加數據(例如“在4行之后將數據附加到該文件”),這很好,但是似乎無法完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM