JaxB封送拆封文件内容

问题描述:

我想使用JaxB来编组我对XML创建的对象。我想要的是创建一个列表,然后将其打印到文件中,然后创建一个新列表并将其打印到同一个文件中,但是每次执行时都会写入第一个列表。我希望最终的XML文件看起来像我只有一个大对象列表。我会这样做,但有很多,我很快将我的堆大小。JaxB封送拆封文件内容

所以,我的主要创建了一堆线程,每个线程遍历它接收的对象列表并在每个对象上调用create_Log。一旦完成,它会调用printToFile,它将列表编组到文件中。

public class LogThread implements Runnable { 
//private Thread myThread; 
private Log_Message message = null; 
private LinkedList<Log_Message> lmList = null; 
LogServer Log = null; 
private String Username = null; 

public LogThread(LinkedList<Log_Message> lmList){ 
    this.lmList = lmList; 
} 

public void run(){ 
    //System.out.println("thread running"); 
    LogServer Log = new LogServer(); 
    //create iterator for list 
    final ListIterator<Log_Message> listIterator = lmList.listIterator(); 

    while(listIterator.hasNext()){ 
     message = listIterator.next(); 
     CountTrans.addTransNumber(message.TransactionNumber); 
     Username = message.input[2]; 
     Log.create_Log(message.input, message.TransactionNumber, message.Message, message.CMD); 
    } 
    Log.printToFile(); 
    init_LogServer.threadCount--; 
    init_LogServer.doneList(); 
    init_LogServer.doneUser(); 
    System.out.println("Thread "+ Thread.currentThread().getId() +" Completed user: "+ Username+"... Number of Users Complete: " + init_LogServer.getUsersComplete()); 
    //Thread.interrupt(); 
} 
} 

上面调用以下功能create_Log构建我从我被赋予了XSD(SystemEventType,QuoteServerType ...等)所生成的新的对象。这些对象都使用下面的函数添加到ArrayList,并附加到Root对象。一旦LogThread循环完成,它会调用printToFile,它从Root对象获取列表并将其编组到文件中......覆盖已经存在的内容。我怎样才能将它添加到同一个文件,而不需要写入,也不需要在堆中创建一个主列表?

public class LogServer { 
public log Root = null; 
public static String fileName = "LogFile.xml"; 
public static File XMLfile = new File(fileName); 

public LogServer(){ 
    this.Root = new log(); 
} 
//output LogFile.xml 
public synchronized void printToFile(){ 
    System.out.println("Printing XML"); 
    //write to xml file 
    try { 
     init_LogServer.marshaller.marshal(Root,XMLfile); 
    } catch (JAXBException e) { 
     e.printStackTrace(); 
    } 
    System.out.println("Done Printing XML"); 
} 


private BigDecimal ConvertStringtoBD(String input){ 
    DecimalFormatSymbols symbols = new DecimalFormatSymbols(); 
    symbols.setGroupingSeparator(','); 
    symbols.setDecimalSeparator('.'); 
    String pattern = "#,##0.0#"; 
    DecimalFormat decimalFormat = new DecimalFormat(pattern, symbols); 
    decimalFormat.setParseBigDecimal(true); 
    // parse the string 
    BigDecimal bigDecimal = new BigDecimal("0"); 
    try { 
     bigDecimal = (BigDecimal) decimalFormat.parse(input); 
    } catch (ParseException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return bigDecimal; 
} 

public QuoteServerType Log_Quote(String[] input, int TransactionNumber){ 
    BigDecimal quote = ConvertStringtoBD(input[4]); 
    BigInteger TransNumber = BigInteger.valueOf(TransactionNumber); 
    BigInteger ServerTimeStamp = new BigInteger(input[6]); 
    Date date = new Date(); 
    long timestamp = date.getTime(); 
    ObjectFactory factory = new ObjectFactory(); 
    QuoteServerType quoteCall = factory.createQuoteServerType(); 

    quoteCall.setTimestamp(timestamp); 
    quoteCall.setServer(input[8]); 
    quoteCall.setTransactionNum(TransNumber); 
    quoteCall.setPrice(quote); 
    quoteCall.setStockSymbol(input[3]); 
    quoteCall.setUsername(input[2]); 
    quoteCall.setQuoteServerTime(ServerTimeStamp); 
    quoteCall.setCryptokey(input[7]); 

    return quoteCall; 
} 
public SystemEventType Log_SystemEvent(String[] input, int TransactionNumber, CommandType CMD){ 
    BigInteger TransNumber = BigInteger.valueOf(TransactionNumber); 
    Date date = new Date(); 
    long timestamp = date.getTime(); 
    ObjectFactory factory = new ObjectFactory(); 
    SystemEventType SysEvent = factory.createSystemEventType(); 

    SysEvent.setTimestamp(timestamp); 
    SysEvent.setServer(input[8]); 
    SysEvent.setTransactionNum(TransNumber); 
    SysEvent.setCommand(CMD); 
    SysEvent.setFilename(fileName); 

    return SysEvent; 
} 

public void create_Log(String[] input, int TransactionNumber, String Message, CommandType Command){ 
    switch(Command.toString()){ 
    case "QUOTE": //Quote_Log 
     QuoteServerType quote_QuoteType = Log_Quote(input,TransactionNumber); 
     Root.getUserCommandOrQuoteServerOrAccountTransaction().add(quote_QuoteType); 
     break; 

    case "QUOTE_CACHED": 
     SystemEventType Quote_Cached_SysType = Log_SystemEvent(input, TransactionNumber, CommandType.QUOTE); 
     Root.getUserCommandOrQuoteServerOrAccountTransaction().add(Quote_Cached_SysType); 
     break; 

} 
} 

编辑:下面是代码的对象是如何加入到ArrayList

public List<Object> getUserCommandOrQuoteServerOrAccountTransaction() { 
    if (userCommandOrQuoteServerOrAccountTransaction == null) { 
     userCommandOrQuoteServerOrAccountTransaction = new ArrayList<Object>(); 
    } 
    return this.userCommandOrQuoteServerOrAccountTransaction; 
} 

JAXB

为约映射Java对象树到XML文档,或反之亦然。所以原则上,在将其保存到xml之前,您需要完整的对象模型。 当然,对于非常大的数据,例如数据库转储,这是不可能的,因此jaxb允许将片段中的对象树编组在一起,让用户控制对象创建和编组的时刻。典型的用例是从数据库中逐一提取记录并将它们一个接一个地整理到一个文件中,所以堆不会有问题。

但是,您正在询问如何将另一个对象树附加到另一个对象(一个新内存中,另一个已经在xml文件中表示)。这通常是不可能的,因为它不是真的附加,而是创建包含两者内容的新对象树(只有一个文档根元素,而不是两个)。

所以,你可以做什么,

  • 是创建新的XML表示用手动启动根 元素,
    • 复制现有的XML内容,以新的XML或者使用XMLStreamWriter/XMLStreamReader的读/写操作或解组日志对象并将它们逐个编组。
    • 将您的日志对象编组到相同的xml stram
    • 完成具有根关闭元素的xml。 -

依稀,这样的事情:

XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileOutputStream(...), StandardCharsets.UTF_8.name()); 
//"mannually" output the beginign of the xml document == its declaration and the root element 
writer.writeStartDocument(); 
writer.writeStartElement("YOUR_ROOT_ELM"); 

Marshaller mar = ... 
mar.setProperty(Marshaller.JAXB_FRAGMENT, true); //instructs jaxb to output only objects not the whole xml document 

PartialUnmarshaler existing = ...; //allows reading one by one xml content from existin file, 

while (existing.hasNext()) { 
    YourObject obj = existing.next(); 
    mar.marshal(obj, writer); 
    writer.flush(); 
} 

List<YourObject> toAppend = ... 
for (YourObject toAppend) { 
    mar.marshal(obj,writer); 
    writer.flush(); 
} 

//finishing the document, closing the root element 
writer.writeEndElement(); 
writer.writeEndDocument(); 

读一个接一个地从大的XML文件,并彻底执行PartialUnmarshaler在这个答案被描述的对象: https://stackoverflow.com/a/9260039/4483840

这是'优雅'的解决方案。 那么优雅是让你的线程写自己的日志列表,单个文件和自己的附加它们。你只需要读取和复制的第一个文件的标题,然后从最后一个结束标记除了复制其所有的内容,复制其他文件忽略文件openkng和结束标记,输出的结束标记的内容。

如果您编组设置为marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,真); 每个打开/关闭标签将在不同的行,所以丑陋的黑客是 所有行从第三复制到一个最后,然后输出结束标记之前。

这是丑陋的黑客攻击,因为它是你的输出格式敏感(如果您examle改变你的容器的根元素)。但比完整的Jaxb解决方案更快实施。