Search code examples
javainputstream

Stop reading inputstream after specified number of bytes


Is there a way to divide an input stream into chunks? For instance, I am sending an input stream to a BodyPublisher, and I would like that BodyPublisher to read a subset of the input stream and stop, then, the next iteration would read the next set of bytes in the input stream.

I guess another way to ask this is, is there an input stream that can wrap another input stream and return end of stream after a specified number of bytes?

It might look something like:

InputStream is = // my inputstream
while (bytesRead < numBytes) {
   SubsetInputStream subsetIs = new SubsetInputStream(is, chunkSize);
   ...
   .POST(HttpRequest.BodyPublishers.ofInputStream(() -> subsetIs));
   ...
   bytesRead += chunkSize;
}

Solution

  • Seems trivial to make it yourself:

    import java.io.*;
    
    public class LimitedInputStream extends FilterInputStream {
      private int limit;
    
      public LimitedInputStream(InputStream in, int limit) {
        super(in);
        if (in == null) throw new NullPointerException("in");
        if (limit < 1) throw new IllegalArgumentException("limit must be positive");
        this.limit = limit;
      }
    
      @Override public int read() throws IOException {
        if (limit < 1) return -1;
        limit--;
        return in.read();
      }
    
      @Override public int read(byte[] b, int off, int len) throws IOException {
        if (limit < 1) return -1;
        int lim = Math.min(len, limit);
        int r = in.read(b, off, lim);
        if (r > 0) limit -= r;
        return r;
      }
    
      @Override public void close() throws IOException {
        in.close();
      }
    
      @Override public long skip(long n) throws IOException {
        long lim = Math.min(n, limit);
        long r = in.skip(lim);
        if (r > 0) limit -= r;
        return r;
      }
    
      @Override public int available() throws IOException {
        return Math.min(in.available(), limit);
      }
    
      public static void main(String[] args) throws Exception {
        var raw = new ByteArrayInputStream(new byte[256]);
        var lim = new LimitedInputStream(raw, 100);
        byte[] b = new byte[55];
        System.out.println(lim.read(b)); // prints 55
        lim.read();
        lim.read();
        System.out.println(lim.read(b)); // prints 43
        System.out.println(lim.read(b)); // prints -1
      }
    }