se.wfh.libs.common.utils.cfr.ChainedFileReaderImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils Show documentation
Show all versions of utils Show documentation
Some helper classes i needed for several projects (Utils)
package se.wfh.libs.common.utils.cfr;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
class ChainedFileReaderImpl {
private CachedInputStream cachedStream = null;
private final boolean cacheStream;
private final List files = Collections
.synchronizedList(new ArrayList<>());
private long nextStart = 0;
private long seqPos = 0;
public ChainedFileReaderImpl(final boolean cacheStream) {
this.cacheStream = cacheStream;
}
public void add(final File next) throws FileNotFoundException {
// add the file to the end of the list
files.add(new FileInfo(next, nextStart));
// set the new start index
nextStart += next.length();
}
public int available() {
return (int) (nextStart - seqPos);
}
public void close() throws IOException {
// if a cached stream is open, close it
if (cachedStream != null) {
cachedStream.getStream().close();
cachedStream = null;
}
}
private void closeStream(final Closeable stream) throws IOException {
if (!cacheStream && stream != null) {
stream.close();
}
}
private void incCached(final int amount) {
if (cachedStream != null) {
cachedStream.incRead(amount);
}
}
public long length() {
return nextStart;
}
public int read(final byte buff[], final int off, final int len)
throws IOException {
int read = read(buff, off, seqPos, len);
if (read > 0) {
seqPos += read;
}
return read;
}
public int read(final byte buff[], final int off, final long pos,
final int len) throws IOException {
int read = 0;
InputStream istream = null;
try {
while (read < len) {
istream = seek(pos + read);
if (istream == null) {
if (read == 0) {
read = -1;
}
break;
}
int cur = istream.read(buff, read + off, len - read);
if (cur == -1) {
continue;
}
read += cur;
incCached(cur);
}
} finally {
closeStream(istream);
}
return read;
}
public void reset() {
seqPos = 0;
}
private InputStream seek(final long pos) throws IOException {
if (pos >= nextStart) {
return null;
}
/* search for cached stream */
InputStream result = seekCachedStream(pos);
if (result != null) {
return result;
}
/*
* just allow one call to this function. as we iterate over the list of
* files, lock on them.
*/
Optional info = files
.stream()
.parallel()
.filter(
elem -> pos >= elem.getStart()
&& pos < elem.getStart() + elem.getLength()).findFirst();
if (info.isPresent()) {
try {
FileInfo match = info.get();
/* open the stream */
result = new FileInputStream(match.getFile());
/* how many bytes we have to skip */
long toSkip = pos - match.getStart();
skipStream(result, toSkip);
/* cache stream */
cachedStream = new CachedInputStream(result, pos - match.getStart(),
match.getStart() + match.getLength());
} finally {
if (cachedStream == null && result != null) {
result.close();
}
}
}
return result;
}
private InputStream seekCachedStream(final long pos) throws IOException {
InputStream result = null;
/* check if the stream we seek is cached */
if (cachedStream == null || !cacheStream) {
return null;
}
/* is the cached stream the right one for the seeked position? */
if (cachedStream.getPos() + seqPos <= pos && cachedStream.getEnd() > pos) {
/* fetch the stream */
InputStream stream = cachedStream.getStream();
/* skip forward the the seeked position */
skipStream(stream, pos - cachedStream.getPos());
/* return the stream */
result = stream;
} else {
/*
* the cached stream is not the right one for the seeked position. Close
* the old one.
*/
cachedStream.getStream().close();
cachedStream = null;
}
return result;
}
public long skip(final long nbr) throws IOException {
/* increment the position index */
seqPos += nbr;
/* return skipped count */
return nbr;
}
private void skipStream(final InputStream result, final long count)
throws IOException {
/* counter for the skipped bytes */
long skipped = 0;
/* number of bytes to skip */
long toSkip = count;
/* as long as there are bytes to skip */
while (toSkip > 0) {
/* try to skip all bytes at once */
skipped = result.skip(toSkip);
/* if skipped return -1, the end of stream has been reached. */
if (skipped < 0) {
continue;
}
/*
* recalculate the bytes we need to skip according to the just
* skipped bytes.
*/
toSkip -= skipped;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy