001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 */ 017package org.apache.commons.io.input; 018 019import static org.apache.commons.io.IOUtils.EOF; 020 021import java.io.IOException; 022import java.io.Reader; 023import java.util.Arrays; 024import java.util.Iterator; 025import java.util.Objects; 026 027/** 028 * Provides the contents of multiple Readers in sequence. 029 * 030 * @since 2.7 031 */ 032public class SequenceReader extends Reader { 033 034 private Reader reader; 035 private Iterator<? extends Reader> readers; 036 037 /** 038 * Construct a new instance with readers 039 * 040 * @param readers the readers to read 041 */ 042 public SequenceReader(final Iterable<? extends Reader> readers) { 043 this.readers = Objects.requireNonNull(readers, "readers").iterator(); 044 this.reader = nextReader(); 045 } 046 047 /** 048 * Construct a new instance with readers 049 * 050 * @param readers the readers to read 051 */ 052 public SequenceReader(final Reader... readers) { 053 this(Arrays.asList(readers)); 054 } 055 056 /* 057 * (non-Javadoc) 058 * 059 * @see java.io.Reader#close() 060 */ 061 @Override 062 public void close() throws IOException { 063 this.readers = null; 064 this.reader = null; 065 } 066 067 /** 068 * Returns the next available reader or null if done. 069 * 070 * @return the next available reader or null 071 */ 072 private Reader nextReader() { 073 return this.readers.hasNext() ? this.readers.next() : null; 074 } 075 076 /* 077 * (non-Javadoc) 078 * 079 * @see java.io.Reader#read(char[], int, int) 080 */ 081 @Override 082 public int read() throws IOException { 083 int c = EOF; 084 while (reader != null) { 085 c = reader.read(); 086 if (c != EOF) { 087 break; 088 } 089 reader = nextReader(); 090 } 091 return c; 092 } 093 094 /* 095 * (non-Javadoc) 096 * 097 * @see java.io.Reader#read() 098 */ 099 @Override 100 public int read(final char[] cbuf, int off, int len) throws IOException { 101 Objects.requireNonNull(cbuf, "cbuf"); 102 if (len < 0 || off < 0 || off + len > cbuf.length) { 103 throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + ", offset=" + off + ", length=" + len); 104 } 105 int count = 0; 106 while (reader != null) { 107 final int readLen = reader.read(cbuf, off, len); 108 if (readLen == EOF) { 109 reader = nextReader(); 110 } else { 111 count += readLen; 112 off += readLen; 113 len -= readLen; 114 if (len <= 0) { 115 break; 116 } 117 } 118 } 119 if (count > 0) { 120 return count; 121 } 122 return EOF; 123 } 124}