StreamUtils { public static InputStream markSupportedInputStream(final InputStream is, final int markBufferSize) { if (is.markSupported()) { return is; } return new InputStream() { byte[] mMarkBuffer; boolean mInMarked = false; boolean mInReset = false; boolean mDry = false; private int mPosition = 0; private int mCount = 0; @Override public int read() throws IOException { if (!mInMarked) { return is.read(); } else { if (mPosition < mCount) { byte b = mMarkBuffer[mPosition++]; return b & 0xFF; } if (!mInReset) { if (mDry) { return -1; } if (null == mMarkBuffer) { mMarkBuffer = new byte[markBufferSize]; } if (mPosition >= markBufferSize) { throw new IOException("Mark buffer is full!"); } int read = is.read(); if (-1 == read) { mDry = true; return -1; } mMarkBuffer[mPosition++] = (byte) read; mCount++; return read; } else { mInMarked = false; mInReset = false; mPosition = 0; mCount = 0; return is.read(); } } } @Override public synchronized void mark(int readlimit) { mInMarked = true; mInReset = false; int count = mCount - mPosition; if (count > 0) { System.arraycopy(mMarkBuffer, mPosition, mMarkBuffer, 0, count); mCount = count; mPosition = 0; } } @Override public synchronized void reset() throws IOException { if (!mInMarked) { throw new IOException("should mark before reset!"); } mInReset = true; mPosition = 0; } @Override public boolean markSupported() { return true; } @Override public int available() throws IOException { int available = is.available(); if (mInMarked && mInReset) { available += mCount - mPosition; } return available; } @Override public void close() throws IOException { is.close(); } }; } private  StreamUtils(); static InputStream limitedInputStream(final InputStream is, final int limit); static InputStream markSupportedInputStream(final InputStream is, final int markBufferSize); static InputStream markSupportedInputStream(final InputStream is); static void skipUnusedStream(InputStream is);  }
@Test public void testMarkSupportedInputStream() throws Exception { InputStream is = StreamUtilsTest.class.getResourceAsStream("/StreamUtilsTest.txt"); assertEquals(10, is.available()); is = new PushbackInputStream(is); assertEquals(10, is.available()); assertFalse(is.markSupported()); is = StreamUtils.markSupportedInputStream(is); assertEquals(10, is.available()); is.mark(0); assertEquals((int) '0', is.read()); assertEquals((int) '1', is.read()); is.reset(); assertEquals((int) '0', is.read()); assertEquals((int) '1', is.read()); assertEquals((int) '2', is.read()); is.mark(0); assertEquals((int) '3', is.read()); assertEquals((int) '4', is.read()); assertEquals((int) '5', is.read()); is.reset(); assertEquals((int) '3', is.read()); assertEquals((int) '4', is.read()); is.mark(0); assertEquals((int) '5', is.read()); assertEquals((int) '6', is.read()); is.reset(); assertEquals((int) '5', is.read()); assertEquals((int) '6', is.read()); assertEquals((int) '7', is.read()); assertEquals((int) '8', is.read()); assertEquals((int) '9', is.read()); assertEquals(-1, is.read()); assertEquals(-1, is.read()); is.mark(0); assertEquals(-1, is.read()); assertEquals(-1, is.read()); is.reset(); assertEquals(-1, is.read()); assertEquals(-1, is.read()); is.close(); }
@Test public void testMarkInputSupport() { Assertions.assertThrows(IOException.class, () -> { InputStream is = StreamUtilsTest.class.getResourceAsStream("/StreamUtilsTest.txt"); try { is = StreamUtils.markSupportedInputStream(new PushbackInputStream(is), 1); is.mark(1); int read = is.read(); assertThat(read, is((int) '0')); is.skip(1); is.read(); } finally { if (is != null) { is.close(); } } }); }
@Test public void testSkipForOriginMarkSupportInput() throws IOException { InputStream is = StreamUtilsTest.class.getResourceAsStream("/StreamUtilsTest.txt"); InputStream newIs = StreamUtils.markSupportedInputStream(is, 1); assertThat(newIs, is(is)); is.close(); }