From 66dee7b4d80fc873130ea728ee7dde86dc96c76f Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 14 Mar 2021 23:21:18 +0000 Subject: [PATCH] [bug-65184] Improve performance of POFSMiniStore getBlockAt. Thanks to sits git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1887657 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/poifs/filesystem/POIFSMiniStore.java | 25 ++++---- .../poi/poifs/filesystem/POIFSStream.java | 59 +++++++++++++++---- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java b/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java index 701dad68a4..623bd99467 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSMiniStore.java @@ -61,20 +61,25 @@ public class POIFSMiniStore extends BlockStore { int bigBlockOffset = byteOffset % _filesystem.getBigBlockSize(); // Now locate the data block for it - Iterator it = _mini_stream.getBlockIterator(); + Iterator it = _mini_stream.getBlockOffsetIterator(); for (int i = 0; i < bigBlockNumber; i++) { it.next(); } - ByteBuffer dataBlock = it.next(); - assert (dataBlock != null); - // Position ourselves, and take a slice - dataBlock.position( - dataBlock.position() + bigBlockOffset - ); - ByteBuffer miniBuffer = dataBlock.slice(); - miniBuffer.limit(POIFSConstants.SMALL_BLOCK_SIZE); - return miniBuffer; + try { + ByteBuffer dataBlock = _filesystem.getBlockAt(it.next()); + assert(dataBlock != null); + + // Position ourselves, and take a slice + dataBlock.position( + dataBlock.position() + bigBlockOffset + ); + ByteBuffer miniBuffer = dataBlock.slice(); + miniBuffer.limit(POIFSConstants.SMALL_BLOCK_SIZE); + return miniBuffer; + } catch (IOException e) { + throw new RuntimeException(e); + } } /** diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java b/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java index 356b78c9f7..8d8f7c575d 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSStream.java @@ -96,6 +96,15 @@ public class POIFSStream implements Iterable return new StreamBlockByteBufferIterator(startBlock); } + Iterator getBlockOffsetIterator() { + if(startBlock == POIFSConstants.END_OF_CHAIN) { + throw new IllegalStateException( + "Can't read from a new stream before it has been written to" + ); + } + return new StreamBlockOffsetIterator(startBlock); + } + /** * Updates the contents of the stream to the new * set of bytes. @@ -140,11 +149,11 @@ public class POIFSStream implements Iterable /** * Class that handles a streaming read of one stream */ - private class StreamBlockByteBufferIterator implements Iterator { + private class StreamBlockOffsetIterator implements Iterator { private final ChainLoopDetector loopDetector; private int nextBlock; - StreamBlockByteBufferIterator(int firstBlock) { + StreamBlockOffsetIterator(int firstBlock) { this.nextBlock = firstBlock; try { this.loopDetector = blockStore.getChainLoopDetector(); @@ -157,19 +166,15 @@ public class POIFSStream implements Iterable return nextBlock != POIFSConstants.END_OF_CHAIN; } - public ByteBuffer next() { + public Integer next() { if (!hasNext()) { throw new NoSuchElementException("Can't read past the end of the stream"); } - try { - loopDetector.claim(nextBlock); - ByteBuffer data = blockStore.getBlockAt(nextBlock); - nextBlock = blockStore.getNextBlock(nextBlock); - return data; - } catch(IOException e) { - throw new RuntimeException(e); - } + loopDetector.claim(nextBlock); + int currentBlock = nextBlock; + nextBlock = blockStore.getNextBlock(nextBlock); + return currentBlock; } public void remove() { @@ -177,6 +182,38 @@ public class POIFSStream implements Iterable } } + /** + * Class that handles a streaming read of one stream + */ + private class StreamBlockByteBufferIterator implements Iterator { + private final StreamBlockOffsetIterator offsetIterator; + + StreamBlockByteBufferIterator(int firstBlock) { + offsetIterator = new StreamBlockOffsetIterator(firstBlock); + } + + public boolean hasNext() { + return offsetIterator.hasNext(); + } + + public ByteBuffer next() { + if (!hasNext()) { + throw new NoSuchElementException("Can't read past the end of the stream"); + } + + try { + return blockStore.getBlockAt(offsetIterator.next()); + } catch(IOException e) { + throw new RuntimeException(e); + } + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + protected class StreamBlockByteBuffer extends OutputStream { byte[] oneByte = new byte[1]; ByteBuffer buffer; -- 2.39.5