SequenceReader.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.io.input;

  18. import static org.apache.commons.io.IOUtils.EOF;

  19. import java.io.IOException;
  20. import java.io.Reader;
  21. import java.io.SequenceInputStream;
  22. import java.util.Arrays;
  23. import java.util.Iterator;
  24. import java.util.Objects;

  25. import org.apache.commons.io.function.Uncheck;

  26. /**
  27.  * Provides the contents of multiple {@link Reader}s in sequence.
  28.  * <p>
  29.  * Like {@link SequenceInputStream} but for {@link Reader} arguments.
  30.  * </p>
  31.  *
  32.  * @since 2.7
  33.  */
  34. public class SequenceReader extends Reader {

  35.     private Reader reader;
  36.     private final Iterator<? extends Reader> readers;

  37.     /**
  38.      * Constructs a new instance with readers
  39.      *
  40.      * @param readers the readers to read
  41.      */
  42.     public SequenceReader(final Iterable<? extends Reader> readers) {
  43.         this.readers = Objects.requireNonNull(readers, "readers").iterator();
  44.         this.reader = Uncheck.get(this::nextReader);
  45.     }

  46.     /**
  47.      * Constructs a new instance with readers
  48.      *
  49.      * @param readers the readers to read
  50.      */
  51.     public SequenceReader(final Reader... readers) {
  52.         this(Arrays.asList(readers));
  53.     }

  54.     /*
  55.      * (non-Javadoc)
  56.      *
  57.      * @see java.io.Reader#close()
  58.      */
  59.     @Override
  60.     public void close() throws IOException {
  61.         do { // NOPMD
  62.              // empty
  63.         } while (nextReader() != null);
  64.     }

  65.     /**
  66.      * Returns the next available reader or null if done.
  67.      *
  68.      * @return the next available reader or null.
  69.      * @throws IOException IOException  If an I/O error occurs.
  70.      */
  71.     private Reader nextReader() throws IOException {
  72.         if (reader != null) {
  73.             reader.close();
  74.         }
  75.         if (readers.hasNext()) {
  76.             reader = readers.next();
  77.         } else {
  78.             reader = null;
  79.         }
  80.         return reader;
  81.     }

  82.     /*
  83.      * (non-Javadoc)
  84.      *
  85.      * @see java.io.Reader#read(char[], int, int)
  86.      */
  87.     @Override
  88.     public int read() throws IOException {
  89.         int c = EOF;
  90.         while (reader != null) {
  91.             c = reader.read();
  92.             if (c != EOF) {
  93.                 break;
  94.             }
  95.             nextReader();
  96.         }
  97.         return c;
  98.     }

  99.     /*
  100.      * (non-Javadoc)
  101.      *
  102.      * @see java.io.Reader#read()
  103.      */
  104.     @Override
  105.     public int read(final char[] cbuf, int off, int len) throws IOException {
  106.         Objects.requireNonNull(cbuf, "cbuf");
  107.         if (len < 0 || off < 0 || off + len > cbuf.length) {
  108.             throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + ", offset=" + off + ", length=" + len);
  109.         }
  110.         int count = 0;
  111.         while (reader != null) {
  112.             final int readLen = reader.read(cbuf, off, len);
  113.             if (readLen == EOF) {
  114.                 nextReader();
  115.             } else {
  116.                 count += readLen;
  117.                 off += readLen;
  118.                 len -= readLen;
  119.                 if (len <= 0) {
  120.                     break;
  121.                 }
  122.             }
  123.         }
  124.         if (count > 0) {
  125.             return count;
  126.         }
  127.         return EOF;
  128.     }
  129. }