我正在尝试使用JaxB将我创建的对象传递给XML。我想要的是创建一个列表,然后将它打印到文件中,然后创建一个新的列表并将其打印到同一个文件中,但是每次我完成它时都会写入第一个文件。我希望最后的XML文件看起来好像只有一个大的对象列表。我会这样做,但有太多,我很快就把我的堆大小最大化了。
因此,我的主创建了一组线程,每个线程遍历它接收到的对象列表,并在每个对象上调用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...etc)。这些对象都使用下面的函数添加到ArrayList中,并附加到根对象。一旦LogThread循环完成,它就调用printToFile,它从根对象获取列表并将其封送到文件中.覆盖已经存在的东西。我怎样才能将它添加到同一个文件中,而不需要在堆中创建一个主列表?
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;
}发布于 2015-03-19 14:03:46
Jaxb是关于将java对象树映射到xml文档,反之亦然。因此,原则上,您需要完整的对象模型才能将其保存到xml中。当然,对于非常大的数据(例如DB转储)来说,这是不可能的,因此jaxb允许在片段中编组对象树,允许用户控制对象创建和封送的时刻。典型的用例是一个接一个地从DB中获取记录,然后一个接一个地将它们编组到一个文件中,这样堆就不会有问题。
但是,您需要将一个对象树附加到另一个对象树(内存中有一个新的对象树,已经在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,true),则每个开始/结束标记将位于不同的行中,因此,丑陋的攻击是在最后一次之前将所有行从第3行复制到第1行,然后输出结束标记。
它是丑陋的黑客,因为它是敏感的输出格式(如果你的例子,改变你的容器根元素)。但比完整的Jaxb解决方案更快实现。
https://stackoverflow.com/questions/29135755
复制相似问题