java JaxB封送拆收器JAR文件内容

fwzugrvs  于 12个月前  发布在  Java
关注(0)|答案(2)|浏览(87)

我尝试使用JaxB将我创建的对象编组到XML中。我想要的是创建一个列表,然后将其打印到文件中,然后创建一个新的列表,并将其打印到同一个文件中,但每次我这样做都会重写第一个。我希望最终的XML文件看起来像我只有一个大的对象列表。我会这样做,但有这么多,我很快就最大化了我的堆大小。
所以,我的main创建了一堆线程,每个线程遍历它接收到的对象列表,并在每个对象上调用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中,并附加到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;
}

gzszwxb4

gzszwxb41#

Jaxb是关于将java对象树Map到xml文档或反之亦然。因此原则上,在将其保存到xml之前,您需要完整的对象模型。当然,对于非常大的数据,例如DB转储,这是不可能的,因此jaxb允许将对象树编组为片段,让用户控制对象创建和封送的时刻。典型的用例是从数据库中逐个获取记录,并将它们逐个封送,一个文件,所以堆不会有问题。
然而,你问的是将一个对象树附加到另一个对象树上(一个在内存中是新的,另一个已经在xml文件中表示了)。这通常是不可能的,因为它不是真正的附加,而是创建包含两者内容的新对象树(只有一个文档根元素,而不是两个)。
所以你能做的,

  • 创建具有手动启动根元素的新XML表示,
  • 使用XMLStreamWriter/XMLStreamReader读/写操作或解组日志对象并逐个封送它们,将现有xml内容复制到新xml。
  • 将日志对象编组到同一xml流中
  • 使用根关闭元素完成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和closing标签,输出结束标签。
如果你的marshaller被设置为marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true);每个开始/结束标记将在不同的行中,所以丑陋的技巧是从第三行复制到最后一行之前的所有行,然后输出结束标记。
这是一个丑陋的黑客,因为它对你的输出格式很敏感(如果你改变了你的容器根元素)。但是比完整的JAXB解决方案实现得更快。

llycmphe

llycmphe2#

如果你想在Java中使用JAXB将新的XML数据附加到现有的文件中,你可以使用BufferedWriterFileWriter来实现这一点。下面是addEtudiant方法的更新版本:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class YourClassName {

    public void addEtudiant(Etudiant etudiant) {
        try {
            etudiant.setIdPerson();
            JAXBContext jaxbcontext = JAXBContext.newInstance(Etudiant.class);
            Marshaller marshaller = jaxbcontext.createMarshaller();

            // Specify the path to your XML file
            String filePath = "PathToYourFile";

            // Use BufferedWriter with FileWriter in append mode
            try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filePath, true)))) {
                marshaller.marshal(etudiant, writer);
            }

            System.out.println("Etudiant written to XML file successfully");

        } catch (JAXBException | IOException e) {
            e.printStackTrace();
        }
    }
}

字符串
这段代码使用try-with-resources来确保BufferedWriter在写入XML数据后正确关闭。请确保将"PathToYourFile"替换为XML文件的实际路径。这种方法允许您将新数据附加到现有的XML文件中,而无需重新配置内容。

相关问题