在 JAXB 反序列化/序列化期间获取进度信息
Posted
技术标签:
【中文标题】在 JAXB 反序列化/序列化期间获取进度信息【英文标题】:Get progress information during JAXB de-/serialization 【发布时间】:2017-08-14 11:16:07 【问题描述】:有没有办法在 JAXB Marshaller 和 Unmarshaller 上注册一些进度监视器? 我想在数据反序列化/序列化时在我的 GUI 中显示一些进度信息。
我看到你可以设置一个Unmarshaller.Listener
和Marshaller.Listener
,它们有一个“之前”和“之后”的方法。不过,我没有看到任何直接的方法来获取要序列化的元素总数。
我显然需要它来计算一些“完成百分比”信息。
【问题讨论】:
【参考方案1】:解组前解析可以吗?
如果是这样,假设您有一个对象列表,您可以执行类似...
final String tagName = *** name of tag you are counting ***;
InputStream in = *** stream of your xml ***;
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
final AtomicInteger counter = new AtomicInteger();
saxParser.parse(in, new DefaultHandler()
@Override
public void startElement (String uri, String localName, String qName, Attributes attributes)
if (localName.equals(tagName))
counter.incrementAndGet();
);
【讨论】:
这可能是一种解决方法。我的 tagName 在 xml 树中不是唯一的怎么办? 然后检查一组名称而不是单个名称。 编组是否类似?【参考方案2】:通过利用 InputStream 来做一个更底层的方法是一个可接受的解决方案吗?
例如
import java.io.IOException;
import java.io.InputStream;
import java.util.function.DoubleConsumer;
public class InputStreamWithProgressDecorator extends InputStream
/** Input stream to be decorated */ private final InputStream inputStream;
/** Amount of byte read */ private long position = 0L;
/** File size */ private final long length;
/** Mark */ private int mark = 0;
/** Consumer of the progress */ private final DoubleConsumer callBack;
public InputStreamWithProgressDecorator(final InputStream is, final long l, final DoubleConsumer cb)
inputStream = is;
length = l;
callBack = cb;
private void setPosition(final long fp)
position = fp;
callBack.accept(getProgress());
public double getProgress()
return length == 0L ? 100d : ((double) position) * 100d / ((double) length);
public long getPosition()
return position;
@Override
public int read(byte[] b) throws IOException
final int rc = inputStream.read(b);
setPosition(position + rc);
return rc;
@Override
public int read(byte[] b, int off, int len) throws IOException
final int rc = inputStream.read(b, off, len);
setPosition(position + rc);
return rc;
@Override
public byte[] readAllBytes() throws IOException
final byte[] result = inputStream.readAllBytes();
setPosition(position + result.length);
return result;
@Override
public byte[] readNBytes(int len) throws IOException
final byte[] result = inputStream.readNBytes(len);
setPosition(position + result.length);
return result;
@Override
public int readNBytes(byte[] b, int off, int len) throws IOException
final int rc = inputStream.readNBytes(b, off, len);
setPosition(position + rc);
return rc;
@Override
public long skip(long n) throws IOException
final long rc = inputStream.skip(n);
setPosition(position + rc);
return rc;
@Override
public int available() throws IOException
return inputStream.available();
@Override
public void close() throws IOException
inputStream.close();
@Override
public synchronized void mark(int readlimit)
inputStream.mark(readlimit);
mark = readlimit;
@Override
public synchronized void reset() throws IOException
inputStream.reset();
setPosition(mark);
@Override
public boolean markSupported()
return inputStream.markSupported();
@Override
public int read() throws IOException
final int c = inputStream.read();
setPosition(position + 1);
return c;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.function.DoubleConsumer;
public class Demo1
public static void main(String[] args) throws IOException
final File file = new File(args[0]);
final DoubleConsumer callBack = p -> System.out.printf("%.0f%%\n", p);
try (final FileInputStream fis = new FileInputStream(file); final InputStreamWithProgressDecorator is = new InputStreamWithProgressDecorator(fis, file.length(), callBack))
// Simulating JAXB unmarshaller reads
byte[] buffer = is.readNBytes(1024);
while (buffer.length != 0) buffer = is.readNBytes(1024);
或者,如果您有一个带有单独线程方法的 FileInputStream:
public class FileInputStreamReadProgressThread extends Thread implements UncaughtExceptionHandler
/** Input stream */ private final FileInputStream fileInputStream;
/** File size */ private final long length;
/** Read progress in percents */ private double progress = 0d;
/** Exception from thread */ private Throwable exception = null;
/** Consumer of the progress */ private final DoubleConsumer callBack;
public FileInputStreamReadProgressThread(final FileInputStream fis, final long l, final DoubleConsumer cb)
fileInputStream = fis;
length = l;
callBack = cb;
setUncaughtExceptionHandler(this);
setName(getClass().getSimpleName());
public double getProgress() return progress;
public Throwable getException() return exception;
@Override public void uncaughtException(final Thread t, final Throwable e) exception = e;
@Override
public void run()
try
long position = -1L;
final FileChannel channel = fileInputStream.getChannel();
while (!isInterrupted() && channel.isOpen() && position < length)
position = channel.position();
progress = length == 0L ? 100d : ((double)position) * 100d / ((double)length);
callBack.accept(progress);
sleep(100L);
catch (final IOException e)
exception = e;
catch (final InterruptedException e)
// Do nothing
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.util.function.DoubleConsumer;
public class Demo2
public static void main(String[] args) throws IOException
final File file = new File(args[0]);
final DoubleConsumer callBack = p -> System.out.printf("%.0f%%\n", p);
try (final FileInputStream fis = new FileInputStream(file); final InputStream is = Channels.newInputStream(fis.getChannel()))
final FileInputStreamReadProgressThread readProgressThread = new FileInputStreamReadProgressThread(fis, file.length(), callBack);
readProgressThread.start();
// Simulating JAXB unmarshaller reads
is.readAllBytes();
【讨论】:
以上是关于在 JAXB 反序列化/序列化期间获取进度信息的主要内容,如果未能解决你的问题,请参考以下文章
如何自定义 SpringWebFlux WebClient xml+rss JAXB 反序列化?