开发者

How can I create constrained InputStream to read only part of the file?

I want to create an InputStream that is limited to a certain range of bytes in file, e.g. to bytes from position 0 to 100. So that the client code should see EOF once 100th byte is re开发者_运维知识库ached.


The read() method of InputStream reads a single byte at a time. You could write a subclass of InputStream that maintains an internal counter; each time read() is called, update the counter. If you have hit your maximum, do not allow any further reads (return -1 or something like that).

You will also need to ensure that the other methods for reading read_int, etc are unsupported (ex: Override them and just throw UnsupportedOperationException());

I don't know what your use case is, but as a bonus you may want to implement buffering as well.


As danben says, just decorate your stream and enforce the constraint:

public class ConstrainedInputStream extends InputStream {
  private final InputStream decorated;
  private long length;

  public ConstrainedInputStream(InputStream decorated, long length) {
    this.decorated = decorated;
    this.length = length;
  }

  @Override public int read() throws IOException {
    return (length-- <= 0) ? -1 : decorated.read();
  }

  // TODO: override other methods if you feel it's necessary
  // optionally, extend FilterInputStream instead
}


Consider using http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/io/LimitInputStream.html


If you only need 100 bytes, then simple is probably best, I'd read them into an array and wrap that as a ByteArrayInputStream. E.g.

   int length = 100;
   byte[] data = new byte[length];
   InputStream in = ...;  //your inputstream
   DataInputStream din = new DataInputStream(din);
   din.readFully(data);
   ByteArrayInputStream first100Bytes = new ByteArrayInputStream(data);
   // pass first100bytes to your clients

If you don't want to use DataInputStream.readFully, there is IOUtils.readFully from apache commons-io, or you can implment the read loop explicitly.

If you have more advanced needs, such as reading from a segment in the middle of the file, or larger amounts of data, then extending InputStream and overriding the read(byte[], int,int) as well as read(), will give you better performance than just overriding the read() method.


You can use guava's ByteStreams. Notice that you should use skipFully() before limit, for example:

ByteStreams.skipFully(tmpStream, range.start());
tmpStream = ByteStreams.limit(tmpStream, range.length());


In addition to this solution, using the skip method of an InputStream, you can also read a range starting in the middle of the file.

public class RangeInputStream extends InputStream
{
    private InputStream parent;
    private long remaining;

    public RangeInputStream(InputStream parent, long start, long end) throws IOException
    {
        if (end < start)
        {
            throw new IllegalArgumentException("end < start");
        }

        if (parent.skip(start) < start)
        {
            throw new IOException("Unable to skip leading bytes");
        }

        this.parent=parent;
        remaining = end - start;
    }

    @Override
    public int read() throws IOException
    {
        return --remaining >= 0 ? parent.read() : -1;
    }
}


I was solved a similar problem for my project, you can see the working code here PartInputStream. I was used it for assets and files input streams. But it is not suitable for а streams whose length is not available initially, such as network streams.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜