private NPOIFSFileSystem(FileChannel channel, boolean closeChannelOnError) throws IOException { this(false); try { // Get the header ByteBuffer headerBuffer = ByteBuffer.allocate(POIFSConstants.SMALLER_BIG_BLOCK_SIZE); IOUtils.readFully(channel, headerBuffer); // Have the header processed _header = new HeaderBlock(headerBuffer); // Now process the various entries _data = new FileBackedDataSource(channel); readCoreContents(); } catch (IOException e) { if (closeChannelOnError) { channel.close(); } throw e; } catch (RuntimeException e) { // Comes from Iterators etc. // TODO Decide if we can handle these better whilst // still sticking to the iterator contract if (closeChannelOnError) { channel.close(); } throw e; } }
/** * Create a POIFSFileSystem from an <tt>InputStream</tt>. Normally the stream is read until EOF. * The stream is always closed. * * <p>Some streams are usable after reaching EOF (typically those that return <code>true</code> * for <tt>markSupported()</tt>). In the unlikely case that the caller has such a stream * <i>and</i> needs to use it after this constructor completes, a work around is to wrap the * stream in order to trap the <tt>close()</tt> call. A convenience method ( * <tt>createNonClosingInputStream()</tt>) has been provided for this purpose: * * <pre> * InputStream wrappedStream = POIFSFileSystem.createNonClosingInputStream(is); * HSSFWorkbook wb = new HSSFWorkbook(wrappedStream); * is.reset(); * doSomethingElse(is); * </pre> * * Note also the special case of <tt>ByteArrayInputStream</tt> for which the <tt>close()</tt> * method does nothing. * * <pre> * ByteArrayInputStream bais = ... * HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.close() ! * bais.reset(); // no problem * doSomethingElse(bais); * </pre> * * @param stream the InputStream from which to read the data * @exception IOException on errors reading, or on invalid data */ public NPOIFSFileSystem(InputStream stream) throws IOException { this(false); ReadableByteChannel channel = null; boolean success = false; try { // Turn our InputStream into something NIO based channel = Channels.newChannel(stream); // Get the header ByteBuffer headerBuffer = ByteBuffer.allocate(POIFSConstants.SMALLER_BIG_BLOCK_SIZE); IOUtils.readFully(channel, headerBuffer); // Have the header processed _header = new HeaderBlock(headerBuffer); // Sanity check the block count BlockAllocationTableReader.sanityCheckBlockCount(_header.getBATCount()); // We need to buffer the whole file into memory when // working with an InputStream. // The max possible size is when each BAT block entry is used int maxSize = BATBlock.calculateMaximumSize(_header); ByteBuffer data = ByteBuffer.allocate(maxSize); // Copy in the header headerBuffer.position(0); data.put(headerBuffer); data.position(headerBuffer.capacity()); // Now read the rest of the stream IOUtils.readFully(channel, data); success = true; // Turn it into a DataSource _data = new ByteArrayBackedDataSource(data.array(), data.position()); } finally { // As per the constructor contract, always close the stream if (channel != null) channel.close(); closeInputStream(stream, success); } // Now process the various entries readCoreContents(); }