001/*-------------------------------------------------------------------------+ 002| | 003| Copyright (c) 2005-2017 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016| | 017+-------------------------------------------------------------------------*/ 018package org.conqat.lib.commons.filesystem; 019 020import java.io.BufferedInputStream; 021import java.io.FileInputStream; 022import java.io.FilterInputStream; 023import java.io.IOException; 024import java.nio.channels.FileChannel; 025 026/** 027 * A wrapper for a {@link FileInputStream} to support marking. This is 028 * preferable over using a {@link BufferedInputStream}, which tries to keep the 029 * entire file in memory (and will fail for large files). 030 * 031 * This solution is based on code from 032 * <a href="https://stackoverflow.com/a/18665678/1237576">here</a>. 033 */ 034public class MarkableFileInputStream extends FilterInputStream { 035 036 /** The underlying channel. */ 037 private final FileChannel channel; 038 039 /** The current mark position. */ 040 private long mark = -1; 041 042 /** Constructor. */ 043 public MarkableFileInputStream(FileInputStream fis) { 044 super(fis); 045 channel = fis.getChannel(); 046 } 047 048 /** {@inheritDoc} */ 049 @Override 050 public boolean markSupported() { 051 return true; 052 } 053 054 /** {@inheritDoc} */ 055 @Override 056 public synchronized void mark(int readlimit) { 057 try { 058 mark = channel.position(); 059 } catch (IOException ex) { 060 mark = -1; 061 } 062 } 063 064 /** {@inheritDoc} */ 065 @Override 066 public synchronized void reset() throws IOException { 067 if (mark == -1) { 068 throw new IOException("Must call mark() before reset()!"); 069 } 070 channel.position(mark); 071 } 072}